packages feed

haskell-igraph 0.7.1 → 0.8.0

raw patch · 759 files changed

+269103/−333 lines, 759 filesdep −colourdep −diagrams-cairodep −diagrams-lib

Dependencies removed: colour, diagrams-cairo, diagrams-lib, hxt, split

Files

ChangeLog.md view
@@ -1,7 +1,15 @@ Revision history for haskell-igraph =================================== -v0.7.1 -- 2018-XX-XX+v0.8.0 -- XXXX-XX-XX+--------------------++* Ship igraph C sources v0.8.0++* Add random number generator.++v0.7.1 -- 2018-11-26+--------------------  * Add a few more functions. 
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2016 Kai Zhang+Copyright (c) 2016-2020 Kai Zhang  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
README.md view
@@ -0,0 +1,2 @@+Haskell bindings to igraph C library+====================================
cbits/haskell_igraph.c view
@@ -1,4 +1,3 @@-#include <igraph/igraph.h> #include "haskell_attributes.h"  const igraph_attribute_table_t igraph_haskell_attribute_table={
haskell-igraph.cabal view
@@ -1,6 +1,7 @@+cabal-version:       2.2 name:                haskell-igraph-version:             0.7.1-synopsis:            Haskell interface of the igraph library.+version:             0.8.0+synopsis:            Bindings to the igraph C library (v0.8.0). description:         igraph<"http://igraph.org/c/"> is a library for creating                      and manipulating large graphs. This package provides the Haskell                      interface of igraph.@@ -8,21 +9,25 @@ license-file:        LICENSE author:              Kai Zhang maintainer:          kai@kzhang.org-copyright:           (c) 2016-2018 Kai Zhang+copyright:           (c) 2016-2020 Kai Zhang category:            Math build-type:          Simple-cabal-version:       >=1.24 extra-source-files:-  include/haskell_igraph.h-  include/bytestring.h-  include/haskell_attributes.h+  include/*.h+  igraph/include/*.h+  igraph/include/*.pmt+  igraph/include/f2c/*.h+  igraph/include/prpack/*.h+  igraph/include/cs/*.h+  igraph/include/cliquer/*.h+  igraph/include/bliss/*.hh+  igraph/include/plfit/*.h+  igraph/AUTHORS+  igraph/COPYING+  stack.yaml   README.md   ChangeLog.md -Flag graphics-  Description: Enable graphics output-  Default:     False- library   exposed-modules:     IGraph.Internal.Initialization@@ -30,13 +35,13 @@     IGraph.Internal     IGraph     IGraph.Mutable+    IGraph.Random     IGraph.Types-    IGraph.Exporter.GEXF     IGraph.Algorithms     IGraph.Algorithms.Structure     IGraph.Algorithms.Community     IGraph.Algorithms.Clique-    IGraph.Algorithms.Layout+    --IGraph.Algorithms.Layout     IGraph.Algorithms.Motif     IGraph.Algorithms.Generators     IGraph.Algorithms.Isomorphism@@ -45,36 +50,579 @@   other-modules:     IGraph.Internal.C2HS -  if flag(graphics)-    exposed-modules: IGraph.Exporter.Graphics--  if flag(graphics)-    build-depends: diagrams-lib, diagrams-cairo-   build-depends:       base >= 4.0 && < 5.0     , bytestring >= 0.9     , cereal-    , colour     , conduit >= 1.3.0     , containers     , data-ordlist     , primitive-    , hxt-    , split     , singletons -  extra-libraries:     igraph+  extra-libraries:     stdc++   hs-source-dirs:      src   default-language:    Haskell2010   ghc-options:         -Wall-  build-tools:         c2hs >=0.25.0+  build-tool-depends: c2hs:c2hs >=0.25.0   c-sources:     cbits/haskell_igraph.c     cbits/haskell_attributes.c     cbits/bytestring.c-  include-dirs:        include +    -- igraph+    igraph/src/abort_.c+    igraph/src/adjlist.c+    igraph/src/arithchk.c+    igraph/src/arpack.c+    igraph/src/array.c+    igraph/src/atlas.c+    igraph/src/attributes.c+    igraph/src/backspac.c+    igraph/src/basic_query.c+    igraph/src/bfgs.c+    igraph/src/bigint.c+    igraph/src/bignum.c+    igraph/src/bipartite.c+    igraph/src/blas.c+    igraph/src/c_abs.c+    igraph/src/cabs.c+    igraph/src/cattributes.c+    igraph/src/c_cos.c+    igraph/src/c_div.c+    igraph/src/centrality.c+    igraph/src/c_exp.c+    igraph/src/cliquer.c+    igraph/src/cliquer_graph.c+    igraph/src/cliques.c+    igraph/src/c_log.c+    igraph/src/close.c+    igraph/src/cocitation.c+    igraph/src/cohesive_blocks.c+    igraph/src/coloring.c+    igraph/src/community.c+    igraph/src/community_leiden.c+    igraph/src/complex.c+    igraph/src/components.c+    igraph/src/conversion.c+    igraph/src/cores.c+    igraph/src/cs_add.c+    igraph/src/cs_amd.c+    igraph/src/cs_chol.c+    igraph/src/cs_cholsol.c+    igraph/src/cs_compress.c+    igraph/src/cs_counts.c+    igraph/src/cs_cumsum.c+    igraph/src/cs_dfs.c+    igraph/src/cs_dmperm.c+    igraph/src/cs_droptol.c+    igraph/src/cs_dropzeros.c+    igraph/src/cs_dupl.c+    igraph/src/cs_entry.c+    igraph/src/cs_ereach.c+    igraph/src/cs_etree.c+    igraph/src/cs_fkeep.c+    igraph/src/cs_gaxpy.c+    igraph/src/cs_happly.c+    igraph/src/cs_house.c+    igraph/src/c_sin.c+    igraph/src/cs_ipvec.c+    igraph/src/cs_leaf.c+    igraph/src/cs_load.c+    igraph/src/cs_lsolve.c+    igraph/src/cs_ltsolve.c+    igraph/src/cs_lu.c+    igraph/src/cs_lusol.c+    igraph/src/cs_malloc.c+    igraph/src/cs_maxtrans.c+    igraph/src/cs_multiply.c+    igraph/src/cs_norm.c+    igraph/src/cs_permute.c+    igraph/src/cs_pinv.c+    igraph/src/cs_post.c+    igraph/src/cs_print.c+    igraph/src/cs_pvec.c+    igraph/src/cs_qr.c+    igraph/src/cs_qrsol.c+    igraph/src/c_sqrt.c+    igraph/src/cs_randperm.c+    igraph/src/cs_reach.c+    igraph/src/cs_scatter.c+    igraph/src/cs_scc.c+    igraph/src/cs_schol.c+    igraph/src/cs_spsolve.c+    igraph/src/cs_sqr.c+    igraph/src/cs_symperm.c+    igraph/src/cs_tdfs.c+    igraph/src/cs_transpose.c+    igraph/src/cs_updown.c+    igraph/src/cs_usolve.c+    igraph/src/cs_util.c+    igraph/src/cs_utsolve.c+    igraph/src/ctype.c+    igraph/src/d_abs.c+    igraph/src/d_acos.c+    igraph/src/d_asin.c+    igraph/src/dasum.c+    igraph/src/d_atan.c+    igraph/src/d_atn2.c+    igraph/src/daxpy.c+    igraph/src/d_cnjg.c+    igraph/src/dcopy.c+    igraph/src/d_cos.c+    igraph/src/d_cosh.c+    igraph/src/d_dim.c+    igraph/src/ddot.c+    igraph/src/decomposition.c+    igraph/src/derf_.c+    igraph/src/derfc_.c+    igraph/src/d_exp.c+    igraph/src/dfe.c+    igraph/src/dgebak.c+    igraph/src/dgebal.c+    igraph/src/dgeev.c+    igraph/src/dgeevx.c+    igraph/src/dgehd2.c+    igraph/src/dgehrd.c+    igraph/src/dgemm.c+    igraph/src/dgemv.c+    igraph/src/dgeqr2.c+    igraph/src/dger.c+    igraph/src/dgesv.c+    igraph/src/dgetf2.c+    igraph/src/dgetrf.c+    igraph/src/dgetrs.c+    igraph/src/dgetv0.c+    igraph/src/dhseqr.c+    igraph/src/d_imag.c+    igraph/src/d_int.c+    igraph/src/disnan.c+    igraph/src/distances.c+    igraph/src/dlabad.c+    igraph/src/dlacn2.c+    igraph/src/dlacpy.c+    igraph/src/dladiv.c+    igraph/src/dlae2.c+    igraph/src/dlaebz.c+    igraph/src/dlaev2.c+    igraph/src/dlaexc.c+    igraph/src/dlagtf.c+    igraph/src/dlagts.c+    igraph/src/dlahqr.c+    igraph/src/dlahr2.c+    igraph/src/dlaisnan.c+    igraph/src/dlaln2.c+    igraph/src/dlamch.c+    igraph/src/dlaneg.c+    igraph/src/dlange.c+    igraph/src/dlanhs.c+    igraph/src/dlanst.c+    igraph/src/dlansy.c+    igraph/src/dlanv2.c+    igraph/src/dlapy2.c+    igraph/src/dlaqr0.c+    igraph/src/dlaqr1.c+    igraph/src/dlaqr2.c+    igraph/src/dlaqr3.c+    igraph/src/dlaqr4.c+    igraph/src/dlaqr5.c+    igraph/src/dlaqrb.c+    igraph/src/dlaqtr.c+    igraph/src/dlar1v.c+    igraph/src/dlarfb.c+    igraph/src/dlarf.c+    igraph/src/dlarfg.c+    igraph/src/dlarft.c+    igraph/src/dlarfx.c+    igraph/src/dlarnv.c+    igraph/src/dlarra.c+    igraph/src/dlarrb.c+    igraph/src/dlarrc.c+    igraph/src/dlarrd.c+    igraph/src/dlarre.c+    igraph/src/dlarrf.c+    igraph/src/dlarrj.c+    igraph/src/dlarrk.c+    igraph/src/dlarrr.c+    igraph/src/dlarrv.c+    igraph/src/dlartg.c+    igraph/src/dlaruv.c+    igraph/src/dlascl.c+    igraph/src/dlaset.c+    igraph/src/dlasq2.c+    igraph/src/dlasq3.c+    igraph/src/dlasq4.c+    igraph/src/dlasq5.c+    igraph/src/dlasq6.c+    igraph/src/dlasr.c+    igraph/src/dlasrt.c+    igraph/src/dlassq.c+    igraph/src/dlaswp.c+    igraph/src/dlasy2.c+    igraph/src/dlatrd.c+    igraph/src/d_lg10.c+    igraph/src/d_log.c+    igraph/src/d_mod.c+    igraph/src/dmout.c+    igraph/src/dnaitr.c+    igraph/src/dnapps.c+    igraph/src/dnaup2.c+    igraph/src/dnaupd.c+    igraph/src/dnconv.c+    igraph/src/dneigh.c+    igraph/src/dneupd.c+    igraph/src/dngets.c+    igraph/src/d_nint.c+    igraph/src/dnrm2.c+    igraph/src/dolio.c+    igraph/src/dorg2r.c+    igraph/src/dorghr.c+    igraph/src/dorgqr.c+    igraph/src/dorm2l.c+    igraph/src/dorm2r.c+    igraph/src/dormhr.c+    igraph/src/dormql.c+    igraph/src/dormqr.c+    igraph/src/dormtr.c+    igraph/src/dotproduct.c+    igraph/src/dpotf2.c+    igraph/src/dpotrf.c+    igraph/src/d_prod.c+    igraph/src/dqueue.c+    igraph/src/drot.c+    igraph/src/dsaitr.c+    igraph/src/dsapps.c+    igraph/src/dsaup2.c+    igraph/src/dsaupd.c+    igraph/src/dscal.c+    igraph/src/dsconv.c+    igraph/src/dseigt.c+    igraph/src/dsesrt.c+    igraph/src/dseupd.c+    igraph/src/dsgets.c+    igraph/src/d_sign.c+    igraph/src/d_sin.c+    igraph/src/d_sinh.c+    igraph/src/dsortc.c+    igraph/src/dsortr.c+    igraph/src/d_sqrt.c+    igraph/src/dstatn.c+    igraph/src/dstats.c+    igraph/src/dstebz.c+    igraph/src/dstein.c+    igraph/src/dstemr.c+    igraph/src/dsteqr.c+    igraph/src/dsterf.c+    igraph/src/dstqrb.c+    igraph/src/dswap.c+    igraph/src/dsyevr.c+    igraph/src/dsymv.c+    igraph/src/dsyr2.c+    igraph/src/dsyr2k.c+    igraph/src/dsyrk.c+    igraph/src/dsytd2.c+    igraph/src/dsytrd.c+    igraph/src/d_tan.c+    igraph/src/d_tanh.c+    igraph/src/dtime_.c+    igraph/src/dtrevc.c+    igraph/src/dtrexc.c+    igraph/src/dtrmm.c+    igraph/src/dtrmv.c+    igraph/src/dtrsen.c+    igraph/src/dtrsm.c+    igraph/src/dtrsna.c+    igraph/src/dtrsv.c+    igraph/src/dtrsyl.c+    igraph/src/due.c+    igraph/src/dummy.c+    igraph/src/dvout.c+    igraph/src/ef1asc_.c+    igraph/src/ef1cmc_.c+    igraph/src/eigen.c+    igraph/src/embedding.c+    igraph/src/endfile.c+    igraph/src/erf_.c+    igraph/src/erfc_.c+    igraph/src/err.c+    igraph/src/error.c+    igraph/src/etime_.c+    igraph/src/exit_.c+    igraph/src/f77_aloc.c+    igraph/src/f77vers.c+    igraph/src/fast_community.c+    igraph/src/feedback_arc_set.c+    igraph/src/flow.c+    igraph/src/fmt.c+    igraph/src/fmtlib.c+    igraph/src/foreign.c+    igraph/src/foreign-dl-lexer.c+    igraph/src/foreign-dl-parser.c+    igraph/src/foreign-gml-lexer.c+    igraph/src/foreign-gml-parser.c+    igraph/src/foreign-graphml.c+    igraph/src/foreign-lgl-lexer.c+    igraph/src/foreign-lgl-parser.c+    igraph/src/foreign-ncol-lexer.c+    igraph/src/foreign-ncol-parser.c+    igraph/src/foreign-pajek-lexer.c+    igraph/src/foreign-pajek-parser.c+    igraph/src/forestfire.c+    igraph/src/fortran_intrinsics.c+    igraph/src/ftell_.c+    igraph/src/games.c+    igraph/src/getenv_.c+    igraph/src/glet.c+    igraph/src/glpk_support.c+    igraph/src/gml_tree.c+    igraph/src/gss.c+    igraph/src/h_abs.c+    igraph/src/hacks.c+    igraph/src/h_dim.c+    igraph/src/h_dnnt.c+    igraph/src/heap.c+    igraph/src/h_indx.c+    igraph/src/h_len.c+    igraph/src/hl_ge.c+    igraph/src/hl_gt.c+    igraph/src/hl_le.c+    igraph/src/hl_lt.c+    igraph/src/h_mod.c+    igraph/src/h_nint.c+    igraph/src/h_sign.c+    igraph/src/i77vers.c+    igraph/src/i_abs.c+    igraph/src/idamax.c+    igraph/src/i_dim.c+    igraph/src/i_dnnt.c+    igraph/src/ieeeck.c+    igraph/src/igraph_buckets.c+    igraph/src/igraph_cliquer.c+    igraph/src/igraph_error.c+    igraph/src/igraph_estack.c+    igraph/src/igraph_fixed_vectorlist.c+    igraph/src/igraph_grid.c+    igraph/src/igraph_hashtable.c+    igraph/src/igraph_heap.c+    igraph/src/igraph_marked_queue.c+    igraph/src/igraph_psumtree.c+    igraph/src/igraph_set.c+    igraph/src/igraph_stack.c+    igraph/src/igraph_strvector.c+    igraph/src/igraph_trie.c+    igraph/src/i_indx.c+    igraph/src/iio.c+    igraph/src/iladlc.c+    igraph/src/iladlr.c+    igraph/src/ilaenv.c+    igraph/src/i_len.c+    igraph/src/ilnw.c+    igraph/src/i_mod.c+    igraph/src/i_nint.c+    igraph/src/inquire.c+    igraph/src/interrupt.c+    igraph/src/iparmq.c+    igraph/src/i_sign.c+    igraph/src/iterators.c+    igraph/src/ivout.c+    igraph/src/kolmogorov.c+    igraph/src/lad.c+    igraph/src/lapack.c+    igraph/src/layout.c+    igraph/src/layout_dh.c+    igraph/src/layout_fr.c+    igraph/src/layout_gem.c+    igraph/src/layout_kk.c+    igraph/src/lbfgs.c+    igraph/src/lbitbits.c+    igraph/src/lbitshft.c+    igraph/src/len_trim.c+    igraph/src/l_ge.c+    igraph/src/l_gt.c+    igraph/src/l_le.c+    igraph/src/l_lt.c+    igraph/src/lread.c+    igraph/src/lsame.c+    igraph/src/lsap.c+    igraph/src/lwrite.c+    igraph/src/matching.c+    igraph/src/math.c+    igraph/src/matrix.c+    igraph/src/maximal_cliques.c+    igraph/src/memory.c+    igraph/src/microscopic_update.c+    igraph/src/mixing.c+    igraph/src/motifs.c+    igraph/src/open.c+    igraph/src/operators.c+    igraph/src/optimal_modularity.c+    igraph/src/options.c+    igraph/src/other.c+    igraph/src/paths.c+    igraph/src/plfit.c+    igraph/src/pow_ci.c+    igraph/src/pow_dd.c+    igraph/src/pow_di.c+    igraph/src/pow_hh.c+    igraph/src/pow_ii.c+    igraph/src/pow_ri.c+    igraph/src/pow_zi.c+    igraph/src/pow_zz.c+    igraph/src/progress.c+    igraph/src/qsort.c+    igraph/src/qsort_r.c+    igraph/src/r_abs.c+    igraph/src/r_acos.c+    igraph/src/random.c+    igraph/src/random_walk.c+    igraph/src/r_asin.c+    igraph/src/r_atan.c+    igraph/src/r_atn2.c+    igraph/src/r_cnjg.c+    igraph/src/r_cos.c+    igraph/src/r_cosh.c+    igraph/src/rdfmt.c+    igraph/src/r_dim.c+    igraph/src/reorder.c+    igraph/src/rewind.c+    igraph/src/r_exp.c+    igraph/src/r_imag.c+    igraph/src/r_int.c+    igraph/src/r_lg10.c+    igraph/src/r_log.c+    igraph/src/r_mod.c+    igraph/src/r_nint.c+    igraph/src/rsfe.c+    igraph/src/r_sign.c+    igraph/src/r_sin.c+    igraph/src/r_sinh.c+    igraph/src/rsli.c+    igraph/src/rsne.c+    igraph/src/r_sqrt.c+    igraph/src/r_tan.c+    igraph/src/r_tanh.c+    igraph/src/sbm.c+    igraph/src/scan.c+    igraph/src/s_cat.c+    igraph/src/scg_approximate_methods.c+    igraph/src/scg.c+    igraph/src/scg_exact_scg.c+    igraph/src/scg_kmeans.c+    igraph/src/scg_optimal_method.c+    igraph/src/scg_utils.c+    igraph/src/s_cmp.c+    igraph/src/s_copy.c+    igraph/src/second.c+    igraph/src/separators.c+    igraph/src/sfe.c+    igraph/src/sig_die.c+    igraph/src/signal_.c+    igraph/src/signbit.c+    igraph/src/sir.c+    igraph/src/spanning_trees.c+    igraph/src/sparsemat.c+    igraph/src/s_paus.c+    igraph/src/spectral_properties.c+    igraph/src/spmatrix.c+    igraph/src/s_rnge.c+    igraph/src/s_stop.c+    igraph/src/statusbar.c+    igraph/src/st-cuts.c+    igraph/src/structural_properties.c+    igraph/src/structure_generators.c+    igraph/src/sue.c+    igraph/src/sugiyama.c+    igraph/src/system_.c+    igraph/src/topology.c+    igraph/src/triangles.c+    igraph/src/type_indexededgelist.c+    igraph/src/types.c+    igraph/src/typesize.c+    igraph/src/uio.c+    igraph/src/uninit.c+    igraph/src/util.c+    igraph/src/vector.c+    igraph/src/vector_ptr.c+    igraph/src/version.c+    igraph/src/visitors.c+    igraph/src/wref.c+    igraph/src/wrtfmt.c+    igraph/src/wsfe.c+    igraph/src/wsle.c+    igraph/src/wsne.c+    igraph/src/xerbla.c+    igraph/src/xwsne.c+    igraph/src/z_abs.c+    igraph/src/z_cos.c+    igraph/src/z_div.c+    igraph/src/zeroin.c+    igraph/src/zeta.c+    igraph/src/z_exp.c+    igraph/src/z_log.c+    igraph/src/z_sin.c+    igraph/src/z_sqrt.c++  cxx-sources:+    igraph/src/clustertool.cpp+    igraph/src/degree_sequence.cpp+    igraph/src/DensityGrid_3d.cpp+    igraph/src/DensityGrid.cpp+    igraph/src/drl_graph_3d.cpp+    igraph/src/drl_graph.cpp+    igraph/src/drl_layout_3d.cpp+    igraph/src/drl_layout.cpp+    igraph/src/drl_parse.cpp+    igraph/src/gengraph_box_list.cpp+    igraph/src/gengraph_degree_sequence.cpp+    igraph/src/gengraph_graph_molloy_hash.cpp+    igraph/src/gengraph_graph_molloy_optimized.cpp+    igraph/src/gengraph_mr-connected.cpp+    igraph/src/gengraph_powerlaw.cpp+    igraph/src/gengraph_random.cpp+    igraph/src/NetDataTypes.cpp+    igraph/src/NetRoutines.cpp+    igraph/src/pottsmodel_2.cpp+    igraph/src/prpack_base_graph.cpp+    igraph/src/prpack.cpp+    igraph/src/prpack_igraph_graph.cpp+    igraph/src/prpack_preprocessed_ge_graph.cpp+    igraph/src/prpack_preprocessed_gs_graph.cpp+    igraph/src/prpack_preprocessed_scc_graph.cpp+    igraph/src/prpack_preprocessed_schur_graph.cpp+    igraph/src/prpack_result.cpp+    igraph/src/prpack_solver.cpp+    igraph/src/prpack_utils.cpp+    igraph/src/walktrap_communities.cpp+    igraph/src/walktrap.cpp+    igraph/src/walktrap_graph.cpp+    igraph/src/walktrap_heap.cpp+    igraph/src/bliss.cc+    igraph/src/bliss_heap.cc+    igraph/src/defs.cc+    igraph/src/graph.cc+    igraph/src/igraph_hrg.cc+    igraph/src/igraph_hrg_types.cc+    igraph/src/infomap.cc+    igraph/src/infomap_FlowGraph.cc+    igraph/src/infomap_Greedy.cc+    igraph/src/infomap_Node.cc+    igraph/src/orbit.cc+    igraph/src/partition.cc+    igraph/src/uintseqhash.cc+    igraph/src/utils.cc++  include-dirs:+    include+    igraph/include+    igraph/include/f2c+    igraph/include/prpack+    igraph/include/cs+    igraph/include/cliquer+    igraph/include/bliss+    igraph/include/plfit+  +  cxx-options: -DPRPACK_IGRAPH_SUPPORT+ test-suite tests   type: exitcode-stdio-1.0   hs-source-dirs: tests@@ -102,3 +650,4 @@ source-repository  head   type: git   location: https://github.com/kaizhang/haskell-igraph.git+
+ igraph/AUTHORS view
@@ -0,0 +1,4 @@+Gabor Csardi <csardi.gabor@gmail.com>+Tamas Nepusz <ntamas@gmail.com>+Szabolcs Horvat <szhorvat@gmail.com>+Vincent Traag <v.a.traag@cwts.leidenuniv.nl>
+ igraph/COPYING view
@@ -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.
+ igraph/include/DensityGrid.h view
@@ -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__+
+ igraph/include/DensityGrid_3d.h view
@@ -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__+
+ igraph/include/NetDataTypes.h view
@@ -0,0 +1,926 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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+
+ igraph/include/NetRoutines.h view
@@ -0,0 +1,61 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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+
+ igraph/include/arith.h view
@@ -0,0 +1,9 @@+#define IEEE_8087+#define Arith_Kind_ASL 1+#define Long int+#define Intcast (int)(long)+#define Double_Align+#define X64_bit_pointers+#define NANCHECK+#define QNaN0 0x0+#define QNaN1 0xfff80000
+ igraph/include/array.pmt view
@@ -0,0 +1,90 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/include/atlas-edges.h view
@@ -0,0 +1,1296 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_types.h"++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, 966, 980, 994, 1008, 1022, 1036, 1050, 1064, 1078, 1092, 1106, 1120, 1134, 1148, 1164, 1180, 1196, 1212, 1228, 1244, 1260, 1276, 1292, 1308, 1324, 1340, 1356, 1372, 1388, 1404, 1420, 1436, 1452, 1468, 1484, 1500, 1516, 1532, 1550, 1568, 1586, 1604, 1622, 1640, 1658, 1676, 1694, 1712, 1730, 1748, 1766, 1784, 1802, 1820, 1838, 1856, 1874, 1892, 1910, 1928, 1946, 1964, 1984, 2004, 2024, 2044, 2064, 2084, 2104, 2124, 2144, 2164, 2184, 2204, 2224, 2244, 2264, 2284, 2304, 2324, 2344, 2364, 2384, 2406, 2428, 2450, 2472, 2494, 2516, 2538, 2560, 2582, 2604, 2626, 2648, 2670, 2692, 2714, 2738, 2762, 2786, 2810, 2834, 2858, 2882, 2906, 2930, 2956, 2982, 3008, 3034, 3060, 3088, 3116, 3146, 3178, 3180, 3184, 3190, 3196, 3204, 3212, 3220, 3228, 3236, 3246, 3256, 3266, 3276, 3286, 3296, 3306, 3316, 3326, 3336, 3348, 3360, 3372, 3384, 3396, 3408, 3420, 3432, 3444, 3456, 3468, 3480, 3492, 3504, 3516, 3528, 3540, 3552, 3564, 3576, 3588, 3602, 3616, 3630, 3644, 3658, 3672, 3686, 3700, 3714, 3728, 3742, 3756, 3770, 3784, 3798, 3812, 3826, 3840, 3854, 3868, 3882, 3896, 3910, 3924, 3938, 3952, 3966, 3980, 3994, 4008, 4022, 4036, 4050, 4064, 4078, 4092, 4106, 4120, 4134, 4148, 4162, 4178, 4194, 4210, 4226, 4242, 4258, 4274, 4290, 4306, 4322, 4338, 4354, 4370, 4386, 4402, 4418, 4434, 4450, 4466, 4482, 4498, 4514, 4530, 4546, 4562, 4578, 4594, 4610, 4626, 4642, 4658, 4674, 4690, 4706, 4722, 4738, 4754, 4770, 4786, 4802, 4818, 4834, 4850, 4866, 4882, 4898, 4914, 4930, 4946, 4962, 4978, 4994, 5010, 5026, 5042, 5058, 5074, 5090, 5106, 5122, 5138, 5154, 5170, 5186, 5202, 5220, 5238, 5256, 5274, 5292, 5310, 5328, 5346, 5364, 5382, 5400, 5418, 5436, 5454, 5472, 5490, 5508, 5526, 5544, 5562, 5580, 5598, 5616, 5634, 5652, 5670, 5688, 5706, 5724, 5742, 5760, 5778, 5796, 5814, 5832, 5850, 5868, 5886, 5904, 5922, 5940, 5958, 5976, 5994, 6012, 6030, 6048, 6066, 6084, 6102, 6120, 6138, 6156, 6174, 6192, 6210, 6228, 6246, 6264, 6282, 6300, 6318, 6336, 6354, 6372, 6390, 6408, 6426, 6444, 6462, 6480, 6498, 6516, 6534, 6552, 6570, 6588, 6606, 6624, 6642, 6660, 6678, 6696, 6714, 6732, 6750, 6768, 6786, 6804, 6822, 6840, 6858, 6876, 6894, 6912, 6930, 6948, 6968, 6988, 7008, 7028, 7048, 7068, 7088, 7108, 7128, 7148, 7168, 7188, 7208, 7228, 7248, 7268, 7288, 7308, 7328, 7348, 7368, 7388, 7408, 7428, 7448, 7468, 7488, 7508, 7528, 7548, 7568, 7588, 7608, 7628, 7648, 7668, 7688, 7708, 7728, 7748, 7768, 7788, 7808, 7828, 7848, 7868, 7888, 7908, 7928, 7948, 7968, 7988, 8008, 8028, 8048, 8068, 8088, 8108, 8128, 8148, 8168, 8188, 8208, 8228, 8248, 8268, 8288, 8308, 8328, 8348, 8368, 8388, 8408, 8428, 8448, 8468, 8488, 8508, 8528, 8548, 8568, 8588, 8608, 8628, 8648, 8668, 8688, 8708, 8728, 8748, 8768, 8788, 8808, 8828, 8848, 8868, 8888, 8908, 8928, 8948, 8968, 8988, 9008, 9028, 9048, 9068, 9088, 9108, 9128, 9148, 9168, 9188, 9208, 9228, 9248, 9268, 9288, 9308, 9328, 9348, 9368, 9388, 9408, 9428, 9448, 9468, 9488, 9508, 9528, 9548, 9568, 9590, 9612, 9634, 9656, 9678, 9700, 9722, 9744, 9766, 9788, 9810, 9832, 9854, 9876, 9898, 9920, 9942, 9964, 9986, 10008, 10030, 10052, 10074, 10096, 10118, 10140, 10162, 10184, 10206, 10228, 10250, 10272, 10294, 10316, 10338, 10360, 10382, 10404, 10426, 10448, 10470, 10492, 10514, 10536, 10558, 10580, 10602, 10624, 10646, 10668, 10690, 10712, 10734, 10756, 10778, 10800, 10822, 10844, 10866, 10888, 10910, 10932, 10954, 10976, 10998, 11020, 11042, 11064, 11086, 11108, 11130, 11152, 11174, 11196, 11218, 11240, 11262, 11284, 11306, 11328, 11350, 11372, 11394, 11416, 11438, 11460, 11482, 11504, 11526, 11548, 11570, 11592, 11614, 11636, 11658, 11680, 11702, 11724, 11746, 11768, 11790, 11812, 11834, 11856, 11878, 11900, 11922, 11944, 11966, 11988, 12010, 12032, 12054, 12076, 12098, 12120, 12142, 12164, 12186, 12208, 12230, 12252, 12274, 12296, 12318, 12340, 12362, 12384, 12406, 12428, 12450, 12472, 12494, 12516, 12538, 12560, 12582, 12604, 12626, 12648, 12670, 12692, 12714, 12736, 12758, 12780, 12802, 12824, 12848, 12872, 12896, 12920, 12944, 12968, 12992, 13016, 13040, 13064, 13088, 13112, 13136, 13160, 13184, 13208, 13232, 13256, 13280, 13304, 13328, 13352, 13376, 13400, 13424, 13448, 13472, 13496, 13520, 13544, 13568, 13592, 13616, 13640, 13664, 13688, 13712, 13736, 13760, 13784, 13808, 13832, 13856, 13880, 13904, 13928, 13952, 13976, 14000, 14024, 14048, 14072, 14096, 14120, 14144, 14168, 14192, 14216, 14240, 14264, 14288, 14312, 14336, 14360, 14384, 14408, 14432, 14456, 14480, 14504, 14528, 14552, 14576, 14600, 14624, 14648, 14672, 14696, 14720, 14744, 14768, 14792, 14816, 14840, 14864, 14888, 14912, 14936, 14960, 14984, 15008, 15032, 15056, 15080, 15104, 15128, 15152, 15176, 15200, 15224, 15248, 15272, 15296, 15320, 15344, 15368, 15392, 15416, 15440, 15464, 15488, 15512, 15536, 15560, 15584, 15608, 15632, 15656, 15680, 15704, 15728, 15752, 15776, 15800, 15824, 15848, 15872, 15896, 15920, 15944, 15968, 15992, 16016, 16040, 16064, 16088, 16112, 16136, 16160, 16184, 16208, 16232, 16256, 16280, 16304, 16328, 16352, 16376, 16402, 16428, 16454, 16480, 16506, 16532, 16558, 16584, 16610, 16636, 16662, 16688, 16714, 16740, 16766, 16792, 16818, 16844, 16870, 16896, 16922, 16948, 16974, 17000, 17026, 17052, 17078, 17104, 17130, 17156, 17182, 17208, 17234, 17260, 17286, 17312, 17338, 17364, 17390, 17416, 17442, 17468, 17494, 17520, 17546, 17572, 17598, 17624, 17650, 17676, 17702, 17728, 17754, 17780, 17806, 17832, 17858, 17884, 17910, 17936, 17962, 17988, 18014, 18040, 18066, 18092, 18118, 18144, 18170, 18196, 18222, 18248, 18274, 18300, 18326, 18352, 18378, 18404, 18430, 18456, 18482, 18508, 18534, 18560, 18586, 18612, 18638, 18664, 18690, 18716, 18742, 18768, 18794, 18820, 18846, 18872, 18898, 18924, 18950, 18976, 19002, 19028, 19054, 19080, 19106, 19132, 19158, 19184, 19210, 19236, 19262, 19288, 19314, 19340, 19366, 19392, 19418, 19444, 19470, 19496, 19522, 19548, 19574, 19600, 19626, 19652, 19678, 19704, 19730, 19756, 19782, 19810, 19838, 19866, 19894, 19922, 19950, 19978, 20006, 20034, 20062, 20090, 20118, 20146, 20174, 20202, 20230, 20258, 20286, 20314, 20342, 20370, 20398, 20426, 20454, 20482, 20510, 20538, 20566, 20594, 20622, 20650, 20678, 20706, 20734, 20762, 20790, 20818, 20846, 20874, 20902, 20930, 20958, 20986, 21014, 21042, 21070, 21098, 21126, 21154, 21182, 21210, 21238, 21266, 21294, 21322, 21350, 21378, 21406, 21434, 21462, 21490, 21518, 21546, 21574, 21602, 21630, 21658, 21686, 21714, 21742, 21770, 21798, 21826, 21854, 21882, 21910, 21938, 21966, 21994, 22022, 22050, 22078, 22106, 22134, 22162, 22190, 22218, 22246, 22274, 22302, 22330, 22358, 22386, 22414, 22442, 22470, 22498, 22528, 22558, 22588, 22618, 22648, 22678, 22708, 22738, 22768, 22798, 22828, 22858, 22888, 22918, 22948, 22978, 23008, 23038, 23068, 23098, 23128, 23158, 23188, 23218, 23248, 23278, 23308, 23338, 23368, 23398, 23428, 23458, 23488, 23518, 23548, 23578, 23608, 23638, 23668, 23698, 23728, 23758, 23788, 23818, 23848, 23878, 23908, 23938, 23968, 23998, 24028, 24058, 24088, 24118, 24148, 24178, 24208, 24238, 24268, 24298, 24328, 24358, 24388, 24418, 24448, 24480, 24512, 24544, 24576, 24608, 24640, 24672, 24704, 24736, 24768, 24800, 24832, 24864, 24896, 24928, 24960, 24992, 25024, 25056, 25088, 25120, 25152, 25184, 25216, 25248, 25280, 25312, 25344, 25376, 25408, 25440, 25472, 25504, 25536, 25568, 25600, 25632, 25664, 25696, 25728, 25760, 25794, 25828, 25862, 25896, 25930, 25964, 25998, 26032, 26066, 26100, 26134, 26168, 26202, 26236, 26270, 26304, 26338, 26372, 26406, 26440, 26474, 26510, 26546, 26582, 26618, 26654, 26690, 26726, 26762, 26798, 26834, 26872, 26910, 26948, 26986, 27024, 27064, 27104, 27146};++__END_DECLS
+ igraph/include/bigint.h view
@@ -0,0 +1,107 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++__BEGIN_DECLS++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
+ igraph/include/bignum.h view
@@ -0,0 +1,125 @@+/*****************************************************************************+ *  Entropy - Emerging Network To Reduce Orwellian Potency Yield+ *+ *  Copyright (C) 2005 Juergen Buchmueller <pullmoll@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 */+/* BN_MAXSIZE used to be 512 here, allowing us to go up to 512*32 = 16384 bits.+ * However, this has caused compilation problems with clang 7.3 (unless+ * compiling with -O2 -g). Since it is unlikely that we'll need that many bits,+ * I have changed this to 128, which still yields 4096 bits of precision but+ * does not cause problems with clang -- TN, 2016-04-18 */+#define BN_MAXSIZE 128+#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_) */
+ igraph/include/bliss/bignum.hh view
@@ -0,0 +1,133 @@+#ifndef BLISS_BIGNUM_HH+#define BLISS_BIGNUM_HH++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++#include <cstdlib>+#include <cstdio>+#include <cmath>+#include <cstring>+#include <sstream>+#include "defs.hh"++#include "igraph_memory.h"+#include "igraph_error.h"++#if defined(BLISS_USE_GMP)+#include <gmp.h>+#endif++namespace bliss {++/**+ * \brief A very simple class for big integers (or approximation of them).+ *+ * If the compile time flag BLISS_USE_GMP is set,+ * then the GNU Multiple Precision Arithmetic library (GMP) is used to+ * obtain arbitrary precision, otherwise "long double" is used to+ * approximate big integers.+ */++#if defined(BLISS_USE_GMP)++class BigNum+{+  mpz_t v;+public:+  /**+   * Create a new big number and set it to zero.+   */+  BigNum() {mpz_init(v); }++  /**+   * Destroy the number.+   */+  ~BigNum() {mpz_clear(v); }++  /**+   * Set the number to \a n.+   */+  void assign(const int n) {mpz_set_si(v, n); }++  /**+   * Multiply the number with \a n.+   */+  void multiply(const int n) {mpz_mul_si(v, v, n); }++  /**+   * Print the number in the file stream \a fp.+   */+  size_t print(FILE* const fp) const {return mpz_out_str(fp, 10, v); }++  int tostring(char **str) const {+    *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++class BigNum+{+  long double v;+public:+  /**+   * Create a new big number and set it to zero.+   */+  BigNum(): v(0.0) {}++  /**+   * Set the number to \a n.+   */+  void assign(const int n) {v = (long double)n; }++  /**+   * Multiply the number with \a n.+   */+  void multiply(const int n) {v *= (long double)n; }++  /**+   * Print the number in the file stream \a fp.+   */+  size_t print(FILE* const fp) const {return fprintf(fp, "%Lg", v); }++  int tostring(char **str) const {+    int size=static_cast<int>( (std::log(std::abs(v))/std::log(10.0))+4 );+    *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++} //namespace bliss++#endif
+ igraph/include/bliss/defs.hh view
@@ -0,0 +1,128 @@+#ifndef BLISS_DEFS_HH+#define BLISS_DEFS_HH++#include <cassert>+#include <cstdarg>++#include "config.h"++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++#if HAVE_GMP == 1+#  define BLISS_USE_GMP+#endif++#ifdef USING_R+#include <R.h>+#define fatal_error(...) (error(__VA_ARGS__))+#endif++namespace bliss {++/**+ * The version number of bliss.+ */+static const char * const version = "0.73";++/*+ * If a fatal error (out of memory, internal error) is encountered,+ * this function is called.+ * There should not be a return from this function but exit or+ * a jump to code that deallocates the AbstractGraph instance that called this.+ */+#ifndef USING_R+void fatal_error(const char* fmt, ...);+#endif+++#if defined(BLISS_DEBUG)+#define BLISS_CONSISTENCY_CHECKS+#define BLISS_EXPENSIVE_CONSISTENCY_CHECKS+#endif+++#if defined(BLISS_CONSISTENCY_CHECKS)+/* Force a check that the found automorphisms are valid */+#define BLISS_VERIFY_AUTOMORPHISMS+#endif+++#if defined(BLISS_CONSISTENCY_CHECKS)+/* Force a check that the generated partitions are equitable */+#define BLISS_VERIFY_EQUITABLEDNESS+#endif++} // namespace bliss++++/*! \mainpage Bliss+ *+ * \section intro_sec Introduction+ *+ * This is the source code documentation of bliss,+ * produced by running <A href="http://www.doxygen.org">doxygen</A> in+ * the source directory.+ * The algorithms and data structures used in bliss are documented in+ * the papers found at the+ * <A href="http://www.tcs.hut.fi/Software/bliss">bliss web site</A>.+ *+ *+ * \section compile_sec Compiling+ *+ * Compiling bliss in Linux should be easy, just execute+ * \code+ * make+ * \endcode+ * in the bliss source directory.+ * This will produce the executable program \c bliss as well as+ * the library file \c libbliss.a that can be linked in other programs.+ * If you have the <A href="http://gmplib.org/">GNU Multiple Precision+ * Arithmetic Library</A> (GMP) installed in your machine, you can also use+ * \code+ * make gmp+ * \endcode+ * to enable exact computation of automorphism group sizes.+ *+ * When linking the bliss library \c libbliss.a in other programs,+ * remember to include the standard c++ library+ * (and the GMP library if you compiled bliss to include it).+ * For instance,+ * \code gcc -o test test.c -lstdc++ -lgmp -lbliss\endcode+ *+ * \section cppapi_sec The C++ language API+ *+ * The C++ language API is the main API to bliss;+ * all other APIs are just more or less complete variants of it.+ * The C++ API consists basically of the public methods in+ * the classes bliss::AbstractGraph, bliss::Graph, and bliss::Digraph.+ * For an example of its use,+ * see the \ref executable "source of the bliss executable".+ *+ *+ * \section capi_sec The C language API+ *+ * The C language API is given in the file bliss_C.h.+ * It is currently more restricted than the C++ API so+ * consider using the C++ API whenever possible.+ */+++#endif
+ igraph/include/bliss/graph.hh view
@@ -0,0 +1,997 @@+#ifndef BLISS_GRAPH_HH+#define BLISS_GRAPH_HH++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++/**+ * \namespace bliss+ * The namespace bliss contains all the classes and functions of the bliss+ * tool except for the C programming language API.+ */+namespace bliss {+  class AbstractGraph;+}++#include <cstdio>+#include <vector>+#include "kstack.hh"+#include "kqueue.hh"+#include "heap.hh"+#include "orbit.hh"+#include "partition.hh"+#include "bignum.hh"+#include "uintseqhash.hh"++namespace bliss {++/**+ * \brief Statistics returned by the bliss search algorithm.+ */+class Stats+{+  friend class AbstractGraph;+public:+  /** \internal The size of the automorphism group. */+  BigNum group_size;+private:+  /** \internal An approximation (due to possible overflows) of+   * the size of the automorphism group. */+  long double group_size_approx;+  /** \internal The number of nodes in the search tree. */+  long unsigned int nof_nodes;+  /** \internal The number of leaf nodes in the search tree. */+  long unsigned int nof_leaf_nodes;+  /** \internal The number of bad nodes in the search tree. */+  long unsigned int nof_bad_nodes;+  /** \internal The number of canonical representative updates. */+  long unsigned int nof_canupdates;+  /** \internal The number of generator permutations. */+  long unsigned int nof_generators;+  /** \internal The maximal depth of the search tree. */+  unsigned long int max_level;+  /** */+  void reset()+  {+    group_size.assign(1);+    group_size_approx = 1.0;+    nof_nodes = 0;+    nof_leaf_nodes = 0;+    nof_bad_nodes = 0;+    nof_canupdates = 0;+    nof_generators = 0;+    max_level = 0;+  }+public:+  Stats() { reset(); }+  /** Print the statistics. */+  size_t print(FILE* const fp) const+  {+    size_t r = 0;+    r += fprintf(fp, "Nodes:          %lu\n", nof_nodes);+    r += fprintf(fp, "Leaf nodes:     %lu\n", nof_leaf_nodes);+    r += fprintf(fp, "Bad nodes:      %lu\n", nof_bad_nodes);+    r += fprintf(fp, "Canrep updates: %lu\n", nof_canupdates);+    r += fprintf(fp, "Generators:     %lu\n", nof_generators);+    r += fprintf(fp, "Max level:      %lu\n", max_level);+    r += fprintf(fp, "|Aut|:          ")+group_size.print(fp)+fprintf(fp, "\n");+    fflush(fp);+    return r;+  }+  /** An approximation (due to possible overflows/rounding errors) of+   * the size of the automorphism group. */+  long double get_group_size_approx() const {return group_size_approx;}+  /** The number of nodes in the search tree. */+  long unsigned int get_nof_nodes() const {return nof_nodes;}+  /** The number of leaf nodes in the search tree. */+  long unsigned int get_nof_leaf_nodes() const {return nof_leaf_nodes;}+  /** The number of bad nodes in the search tree. */+  long unsigned int get_nof_bad_nodes() const {return nof_bad_nodes;}+  /** The number of canonical representative updates. */+  long unsigned int get_nof_canupdates() const {return nof_canupdates;}+  /** The number of generator permutations. */+  long unsigned int get_nof_generators() const {return nof_generators;}+  /** The maximal depth of the search tree. */+  unsigned long int get_max_level() const {return max_level;}+};+++++++/**+ * \brief An abstract base class for different types of graphs.+ */+class AbstractGraph+{+  friend class Partition;++public:+  AbstractGraph();+  virtual ~AbstractGraph();++  /**+   * Set the verbose output level for the algorithms.+   * \param level  the level of verbose output, 0 means no verbose output+   */+  void set_verbose_level(const unsigned int level);++  /**+   * Set the file stream for the verbose output.+   * \param fp  the file stream; if null, no verbose output is written+   */+  void set_verbose_file(FILE * const fp);++  /**+   * Add a new vertex with color \a color in the graph and return its index.+   */+  virtual unsigned int add_vertex(const unsigned int color = 0) = 0;++  /**+   * Add an edge between vertices \a source and \a target.+   * Duplicate edges between vertices are ignored but try to avoid introducing+   * them in the first place as they are not ignored immediately but will+   * consume memory and computation resources for a while.+   */+  virtual void add_edge(const unsigned int source, const unsigned int target) = 0;++  /**+   * Change the color of the vertex \a vertex to \a color.+   */+  virtual void change_color(const unsigned int vertex, const unsigned int color) = 0;++  /**+   * Check whether \a perm is an automorphism of this graph.+   * Unoptimized, mainly for debugging purposes.+   */+  virtual bool is_automorphism(const std::vector<unsigned int>& perm) const;+++  /** Activate/deactivate failure recording.+   * May not be called during the search, i.e. from an automorphism reporting+   * hook function.+   * \param active  if true, activate failure recording, deactivate otherwise+   */+  void set_failure_recording(const bool active) {assert(!in_search); opt_use_failure_recording = active;}++  /** Activate/deactivate component recursion.+   * The choice affects the computed canonical labelings;+   * therefore, if you want to compare whether two graphs are isomorphic by+   * computing and comparing (for equality) their canonical versions,+   * be sure to use the same choice for both graphs.+   * May not be called during the search, i.e. from an automorphism reporting+   * hook function.+   * \param active  if true, activate component recursion, deactivate otherwise+   */+  void set_component_recursion(const bool active) {assert(!in_search); opt_use_comprec = active;}++++  /**+   * Return the number of vertices in the graph.+   */+  virtual unsigned int get_nof_vertices() const = 0;++  /**+   * Return a new graph that is the result of applying the permutation \a perm+   * to this graph. This graph is not modified.+   * \a perm must contain N=this.get_nof_vertices() elements and be a bijection+   * on {0,1,...,N-1}, otherwise the result is undefined or a segfault.+   */+  virtual AbstractGraph* permute(const unsigned int* const perm) const = 0;+  virtual AbstractGraph* permute(const std::vector<unsigned int>& perm) const = 0;++  /**+   * Find a set of generators for the automorphism group of the graph.+   * The function \a hook (if non-null) is called each time a new generator+   * for the automorphism group is found.+   * The first argument \a user_param for the hook is the+   * \a hook_user_param given below,+   * the second argument \a n is the length of the automorphism (equal to+   * get_nof_vertices()) and+   * the third argument \a aut is the automorphism+   * (a bijection on {0,...,get_nof_vertices()-1}).+   * The memory for the automorphism \a aut will be invalidated immediately+   * after the return from the hook function;+   * if you want to use the automorphism later, you have to take a copy of it.+   * Do not call any member functions in the hook.+   * The search statistics are copied in \a stats.+   */+  void find_automorphisms(Stats& stats,+			  void (*hook)(void* user_param,+				       unsigned int n,+				       const unsigned int* aut),+			  void* hook_user_param);++  /**+   * Otherwise the same as find_automorphisms() except that+   * a canonical labeling of the graph (a bijection on+   * {0,...,get_nof_vertices()-1}) is returned.+   * The memory allocated for the returned canonical labeling will remain+   * valid only until the next call to a member function with the exception+   * that constant member functions (for example, bliss::Graph::permute()) can+   * be called without invalidating the labeling.+   * To compute the canonical version of an undirected graph, call this+   * function and then bliss::Graph::permute() with the returned canonical+   * labeling.+   * Note that the computed canonical version may depend on the applied version+   * of bliss as well as on some other options (for instance, the splitting+   * heuristic selected with bliss::Graph::set_splitting_heuristic()).+   */+  const unsigned int* canonical_form(Stats& stats,+				     void (*hook)(void* user_param,+						  unsigned int n,+						  const unsigned int* aut),+				     void* hook_user_param);++  /**+   * Write the graph to a file in a variant of the DIMACS format.+   * See the <A href="http://www.tcs.hut.fi/Software/bliss/">bliss website</A>+   * for the definition of the file format.+   * Note that in the DIMACS file the vertices are numbered from 1 to N while+   * in this C++ API they are from 0 to N-1.+   * Thus the vertex n in the file corresponds to the vertex n-1 in the API.+   * \param fp  the file stream where the graph is written+   */+  virtual void write_dimacs(FILE * const fp) = 0;++  /**+   * Write the graph to a file in the graphviz dotty format.+   * \param fp  the file stream where the graph is written+   */+  virtual void write_dot(FILE * const fp) = 0;++  /**+   * Write the graph in a file in the graphviz dotty format.+   * Do nothing if the file cannot be written.+   * \param file_name  the name of the file to which the graph is written+   */+  virtual void write_dot(const char * const file_name) = 0;++  /**+   * Get a hash value for the graph.+   * \return  the hash value+   */ +  virtual unsigned int get_hash() = 0;++  /**+   * Disable/enable the "long prune" method.+   * The choice affects the computed canonical labelings;+   * therefore, if you want to compare whether two graphs are isomorphic by+   * computing and comparing (for equality) their canonical versions,+   * be sure to use the same choice for both graphs.+   * May not be called during the search, i.e. from an automorphism reporting+   * hook function.+   * \param active  if true, activate "long prune", deactivate otherwise+   */+  void set_long_prune_activity(const bool active) {+    assert(!in_search);+    opt_use_long_prune = active;+  }++++protected:+  /** \internal+   * How much verbose output is produced (0 means none) */+  unsigned int verbose_level;+  /** \internal+   * The output stream for verbose output. */+  FILE *verbstr;+protected:++  /** \internal+   * The ordered partition used in the search algorithm. */+  Partition p;++  /** \internal+   * Whether the search for automorphisms and a canonical labeling is+   * in progress.+   */+  bool in_search;++  /** \internal+   * Is failure recording in use?+   */+  bool opt_use_failure_recording;+  /* The "tree-specific" invariant value for the point when current path+   * got different from the first path */+  unsigned int failure_recording_fp_deviation;++  /** \internal+   * Is component recursion in use?+   */+  bool opt_use_comprec;+++  unsigned int refine_current_path_certificate_index;+  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;++  static const unsigned int CERT_SPLIT = 0; //UINT_MAX;+  static const unsigned int CERT_EDGE  = 1; //UINT_MAX-1;+  /** \internal+   * Add a triple (v1,v2,v3) in the certificate.+   * May modify refine_equal_to_first and refine_cmp_to_best.+   * May also update eqref_hash and failure_recording_fp_deviation. */+  void cert_add(const unsigned int v1,+		const unsigned int v2,+		const unsigned int v3);++  /** \internal+   * Add a redundant triple (v1,v2,v3) in the certificate.+   * Can also just dicard the triple.+   * May modify refine_equal_to_first and refine_cmp_to_best.+   * May also update eqref_hash and failure_recording_fp_deviation. */+  void cert_add_redundant(const unsigned int x,+			  const unsigned int y,+			  const unsigned int z);++  /**\internal+   * Is the long prune method in use?+   */+  bool opt_use_long_prune;+  /**\internal+   * Maximum amount of memory (in megabytes) available for+   * the long prune method+   */+  static const unsigned int long_prune_options_max_mem = 50;+  /**\internal+   * Maximum amount of automorphisms stored for the long prune method;+   * less than this is stored if the memory limit above is reached first+   */+  static const unsigned int long_prune_options_max_stored_auts = 100;++  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;+  /** \internal+   * Initialize the "long prune" data structures.+   */+  void long_prune_init();+  /** \internal+   * Release the memory allocated for "long prune" data structures.+   */+  void long_prune_deallocate();+  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_allocget_fixed(const unsigned int index);+  std::vector<bool>& long_prune_get_mcrs(const unsigned int index);+  std::vector<bool>& long_prune_allocget_mcrs(const unsigned int index);+  /** \internal+   * Swap the i:th and j:th stored automorphism information;+   * i and j must be "in window, i.e. in [long_prune_begin,long_prune_end[+   */+  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(Partition::Cell *) = 0;+  virtual bool split_neighbourhood_of_cell(Partition::Cell * const) = 0;+  void refine_to_equitable();+  void refine_to_equitable(Partition::Cell * const unit_cell);+  void refine_to_equitable(Partition::Cell * const unit_cell1,+			   Partition::Cell * const unit_cell2);+++  /** \internal+   * \return false if it was detected that the current certificate+   *         is different from the first and/or best (whether this is checked+   *         depends on in_search and refine_compare_certificate flags.+   */+  bool do_refine_to_equitable();++  unsigned int eqref_max_certificate_index;+  /** \internal+   * Whether eqref_hash is updated during equitable refinement process.+   */+  bool compute_eqref_hash;+  UintSeqHash eqref_hash;+++  /** \internal+   * Check whether the current partition p is equitable.+   * Performance: very slow, use only for debugging purposes.+   */+  virtual bool is_equitable() const = 0;++  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_index;+  virtual void initialize_certificate() = 0;++  virtual void remove_duplicate_edges() = 0;+  virtual void make_initial_equitable_partition() = 0;+  virtual Partition::Cell* find_next_cell_to_be_splitted(Partition::Cell *cell) = 0;+++  void search(const bool canonical, Stats &stats);+++  void (*report_hook)(void *user_param,+		      unsigned int n,+		      const unsigned int *aut);+  void *report_user_param;+++  /*+   *+   * Nonuniform component recursion (NUCR)+   *+   */++  /** The currently traversed component */+  unsigned int cr_level;++  /** \internal+   * The "Component End Point" data structure+   */+  class CR_CEP {+  public:+    /** At which level in the search was this CEP created */+    unsigned int creation_level;+    /** The current component has been fully traversed when the partition has+     * this many discrete cells left */+    unsigned int discrete_cell_limit;+    /** The component to be traversed after the current one */+    unsigned int next_cr_level;+    /** The next component end point */+    unsigned int next_cep_index;+    bool first_checked;+    bool best_checked;+  };+  /** \internal+   * A stack for storing Component End Points+   */+  std::vector<CR_CEP> cr_cep_stack;++  /** \internal+   * Find the first non-uniformity component at the component recursion+   * level \a level.+   * The component is stored in \a cr_component.+   * If no component is found, \a cr_component is empty.+   * Returns false if all the cells in the component recursion level \a level+   * were discrete.+   * Modifies the max_ival and max_ival_count fields of Partition:Cell+   * (assumes that they are 0 when called and+   *  quarantees that they are 0 when returned).+   */+  virtual bool nucr_find_first_component(const unsigned int level) = 0;+  virtual bool nucr_find_first_component(const unsigned int level,+					 std::vector<unsigned int>& component,+					 unsigned int& component_elements,+					 Partition::Cell*& sh_return) = 0;+  /** \internal+   * The non-uniformity component found by nucr_find_first_component()+   * is stored here.+   */+  std::vector<unsigned int> cr_component;+  /** \internal+   * The number of vertices in the component \a cr_component+   */+  unsigned int cr_component_elements;+++++};++++/**+ * \brief The class for undirected, vertex colored graphs.+ *+ * Multiple edges between vertices are not allowed (i.e., are ignored).+ */+class Graph : public AbstractGraph+{+public:+  /**+   * The possible splitting heuristics.+   * The selected splitting heuristics affects the computed canonical+   * labelings; therefore, if you want to compare whether two graphs+   * are isomorphic by computing and comparing (for equality) their+   * canonical versions, be sure to use the same splitting heuristics+   * for both graphs.+   */+  typedef enum {+    /** First non-unit cell.+     * Very fast but may result in large search spaces on difficult graphs.+     * Use for large but easy graphs. */+    shs_f = 0,+    /** First smallest non-unit cell.+     * Fast, should usually produce smaller search spaces than shs_f. */+    shs_fs,+    /** First largest non-unit cell.+     * Fast, should usually produce smaller search spaces than shs_f. */+    shs_fl,+    /** First maximally non-trivially connected non-unit cell.+     * Not so fast, should usually produce smaller search spaces than shs_f,+     * shs_fs, and shs_fl. */+    shs_fm,+    /** First smallest maximally non-trivially connected non-unit cell.+     * Not so fast, should usually produce smaller search spaces than shs_f,+     * shs_fs, and shs_fl. */+    shs_fsm,+    /** First largest maximally non-trivially connected non-unit cell.+     * Not so fast, should usually produce smaller search spaces than shs_f,+     * shs_fs, and shs_fl. */+    shs_flm+  } SplittingHeuristic;++protected:+  class Vertex {+  public:+    Vertex();+    ~Vertex();+    void add_edge(const unsigned int other_vertex);+    void remove_duplicate_edges(std::vector<bool>& tmp);+    void sort_edges();++    unsigned int color;+    std::vector<unsigned int> edges;+    unsigned int nof_edges() const {return edges.size(); }+  };+  std::vector<Vertex> vertices;+  void sort_edges();+  void remove_duplicate_edges();++  /** \internal+   * Partition independent invariant.+   * Returns the color of the vertex.+   * Time complexity: O(1).+   */+  static unsigned int vertex_color_invariant(const Graph* const g,+					     const unsigned int v);+  /** \internal+   * Partition independent invariant.+   * Returns the degree of the vertex.+   * DUPLICATE EDGES MUST HAVE BEEN REMOVED BEFORE.+   * Time complexity: O(1).+   */+  static unsigned int degree_invariant(const Graph* const g,+				       const unsigned int v);+  /** \internal+   * Partition independent invariant.+   * Returns 1 if there is an edge from the vertex to itself, 0 if not.+   * Time complexity: O(k), where k is the number of edges leaving the vertex.+   */+  static unsigned int selfloop_invariant(const Graph* const g,+					 const unsigned int v);+++  bool refine_according_to_invariant(unsigned int (*inv)(const Graph* const g,+							 const unsigned int v));++  /*+   * Routines needed when refining the partition p into equitable+   */+  bool split_neighbourhood_of_unit_cell(Partition::Cell *);+  bool split_neighbourhood_of_cell(Partition::Cell * const);++  /** \internal+   * \copydoc AbstractGraph::is_equitable() const+   */+  bool is_equitable() const;++  /* Splitting heuristics, documented in more detail in graph.cc */+  SplittingHeuristic sh;+  Partition::Cell* find_next_cell_to_be_splitted(Partition::Cell *cell);+  Partition::Cell* sh_first();+  Partition::Cell* sh_first_smallest();+  Partition::Cell* sh_first_largest();+  Partition::Cell* sh_first_max_neighbours();+  Partition::Cell* sh_first_smallest_max_neighbours();+  Partition::Cell* sh_first_largest_max_neighbours();+++  void make_initial_equitable_partition();++  void initialize_certificate();+  +  bool is_automorphism(unsigned int* const perm);+++  bool nucr_find_first_component(const unsigned int level);+  bool nucr_find_first_component(const unsigned int level,+				 std::vector<unsigned int>& component,+				 unsigned int& component_elements,+				 Partition::Cell*& sh_return);++++public:+  /**+   * Create a new graph with \a N vertices and no edges.+   */+  Graph(const unsigned int N = 0);++  /**+   * Destroy the graph.+   */+  ~Graph();++  /**+   * Read the graph from the file \a fp in a variant of the DIMACS format.+   * See the <A href="http://www.tcs.hut.fi/Software/bliss/">bliss website</A>+   * for the definition of the file format.+   * Note that in the DIMACS file the vertices are numbered from 1 to N while+   * in this C++ API they are from 0 to N-1.+   * Thus the vertex n in the file corresponds to the vertex n-1 in the API.+   *+   * \param fp      the file stream for the graph file+   * \param errstr  if non-null, the possible error messages are printed+   *                in this file stream+   * \return        a new Graph object or 0 if reading failed for some+   *                reason+   */+  static Graph* read_dimacs(FILE* const fp, FILE* const errstr = stderr);++  /**+   * Write the graph to a file in a variant of the DIMACS format.+   * See the <A href="http://www.tcs.hut.fi/Software/bliss/">bliss website</A>+   * for the definition of the file format.+   */+  void write_dimacs(FILE* const fp);++  /**+   * \copydoc AbstractGraph::write_dot(FILE * const fp)+   */+  void write_dot(FILE* const fp);++  /**+   * \copydoc AbstractGraph::write_dot(const char * const file_name)+   */+  void write_dot(const char* const file_name);++  /**+   * \copydoc AbstractGraph::is_automorphism(const std::vector<unsigned int>& perm) const+   */+  bool is_automorphism(const std::vector<unsigned int>& perm) const;+++  /**+   * \copydoc AbstractGraph::get_hash()+   */ +  virtual unsigned int get_hash();++  /**+   * Return the number of vertices in the graph.+   */+  unsigned int get_nof_vertices() const {return vertices.size(); }++  /**+   * \copydoc AbstractGraph::permute(const unsigned int* const perm) const+   */+  Graph* permute(const unsigned int* const perm) const;+  Graph* permute(const std::vector<unsigned int>& perm) const;+  +  /**+   * Add a new vertex with color \a color in the graph and return its index.+   */+  unsigned int add_vertex(const unsigned int color = 0);++  /**+   * Add an edge between vertices \a v1 and \a v2.+   * Duplicate edges between vertices are ignored but try to avoid introducing+   * them in the first place as they are not ignored immediately but will+   * consume memory and computation resources for a while.+   */+  void add_edge(const unsigned int v1, const unsigned int v2);++  /**+   * Change the color of the vertex \a vertex to \a color.+   */+  void change_color(const unsigned int vertex, const unsigned int color);++  /**+   * Compare this graph with the graph \a other.+   * Returns 0 if the graphs are equal, and a negative (positive) integer+   * if this graph is "smaller than" ("greater than", resp.) than \a other.+   */+  int cmp(Graph& other);++  /**+   * Set the splitting heuristic used by the automorphism and canonical+   * labeling algorithm.+   * The selected splitting heuristics affects the computed canonical+   * labelings; therefore, if you want to compare whether two graphs+   * are isomorphic by computing and comparing (for equality) their+   * canonical versions, be sure to use the same splitting heuristics+   * for both graphs.+   */+  void set_splitting_heuristic(const SplittingHeuristic shs) {sh = shs; }+  ++};++++/**+ * \brief The class for directed, vertex colored graphs.+ *+ * Multiple edges between vertices are not allowed (i.e., are ignored).+ */+class Digraph : public AbstractGraph+{+public:+  /**+   * The possible splitting heuristics.+   * The selected splitting heuristics affects the computed canonical+   * labelings; therefore, if you want to compare whether two graphs+   * are isomorphic by computing and comparing (for equality) their+   * canonical versions, be sure to use the same splitting heuristics+   * for both graphs.+   */+  typedef enum {+    /** First non-unit cell.+     * Very fast but may result in large search spaces on difficult graphs.+     * Use for large but easy graphs. */+    shs_f = 0,+    /** First smallest non-unit cell.+     * Fast, should usually produce smaller search spaces than shs_f. */+    shs_fs,+    /** First largest non-unit cell.+     * Fast, should usually produce smaller search spaces than shs_f. */+    shs_fl,+    /** First maximally non-trivially connected non-unit cell.+     * Not so fast, should usually produce smaller search spaces than shs_f,+     * shs_fs, and shs_fl. */+    shs_fm,+    /** First smallest maximally non-trivially connected non-unit cell.+     * Not so fast, should usually produce smaller search spaces than shs_f,+     * shs_fs, and shs_fl. */+    shs_fsm,+    /** First largest maximally non-trivially connected non-unit cell.+     * Not so fast, should usually produce smaller search spaces than shs_f,+     * shs_fs, and shs_fl. */+    shs_flm+  } SplittingHeuristic;++protected:+  class Vertex {+  public:+    Vertex();+    ~Vertex();+    void add_edge_to(const unsigned int dest_vertex);+    void add_edge_from(const unsigned int source_vertex);+    void remove_duplicate_edges(std::vector<bool>& tmp);+    void sort_edges();+    unsigned int color;+    std::vector<unsigned int> edges_out;+    std::vector<unsigned int> edges_in;+    unsigned int nof_edges_in() const {return edges_in.size(); }+    unsigned int nof_edges_out() const {return edges_out.size(); }+  };+  std::vector<Vertex> vertices;+  void remove_duplicate_edges();++  /** \internal+   * Partition independent invariant.+   * Returns the color of the vertex.+   * Time complexity: O(1).+   */+  static unsigned int vertex_color_invariant(const Digraph* const g,+					     const unsigned int v);+  /** \internal+   * Partition independent invariant.+   * Returns the indegree of the vertex.+   * DUPLICATE EDGES MUST HAVE BEEN REMOVED BEFORE.+   * Time complexity: O(1).+   */+  static unsigned int indegree_invariant(const Digraph* const g,+					 const unsigned int v);+  /** \internal+   * Partition independent invariant.+   * Returns the outdegree of the vertex.+   * DUPLICATE EDGES MUST HAVE BEEN REMOVED BEFORE.+   * Time complexity: O(1).+   */+  static unsigned int outdegree_invariant(const Digraph* const g,+					  const unsigned int v);+  /** \internal+   * Partition independent invariant.+   * Returns 1 if there is an edge from the vertex to itself, 0 if not.+   * Time complexity: O(k), where k is the number of edges leaving the vertex.+   */+  static unsigned int selfloop_invariant(const Digraph* const g,+					 const unsigned int v);++  /** \internal+   * Refine the partition \a p according to+   * the partition independent invariant \a inv.+   */+  bool refine_according_to_invariant(unsigned int (*inv)(const Digraph* const g,+							 const unsigned int v));++  /*+   * Routines needed when refining the partition p into equitable+   */+  bool split_neighbourhood_of_unit_cell(Partition::Cell* const);+  bool split_neighbourhood_of_cell(Partition::Cell* const);+++  /** \internal+   * \copydoc AbstractGraph::is_equitable() const+   */+  bool is_equitable() const;++  /* Splitting heuristics, documented in more detail in the cc-file. */+  SplittingHeuristic sh;+  Partition::Cell* find_next_cell_to_be_splitted(Partition::Cell *cell);+  Partition::Cell* sh_first();+  Partition::Cell* sh_first_smallest();+  Partition::Cell* sh_first_largest();+  Partition::Cell* sh_first_max_neighbours();+  Partition::Cell* sh_first_smallest_max_neighbours();+  Partition::Cell* sh_first_largest_max_neighbours();++  void make_initial_equitable_partition();++  void initialize_certificate();++  bool is_automorphism(unsigned int* const perm);++  void sort_edges();++  bool nucr_find_first_component(const unsigned int level);+  bool nucr_find_first_component(const unsigned int level,+				 std::vector<unsigned int>& component,+				 unsigned int& component_elements,+				 Partition::Cell*& sh_return);++public:+  /**+   * Create a new directed graph with \a N vertices and no edges.+   */+  Digraph(const unsigned int N = 0);++  /**+   * Destroy the graph.+   */+  ~Digraph();++  /**+   * Read the graph from the file \a fp in a variant of the DIMACS format.+   * See the <A href="http://www.tcs.hut.fi/Software/bliss/">bliss website</A>+   * for the definition of the file format.+   * Note that in the DIMACS file the vertices are numbered from 1 to N while+   * in this C++ API they are from 0 to N-1.+   * Thus the vertex n in the file corresponds to the vertex n-1 in the API.+   * \param fp      the file stream for the graph file+   * \param errstr  if non-null, the possible error messages are printed+   *                in this file stream+   * \return        a new Digraph object or 0 if reading failed for some+   *                reason+   */+  static Digraph* read_dimacs(FILE* const fp, FILE* const errstr = stderr);++  /**+   * \copydoc AbstractGraph::write_dimacs(FILE * const fp)+   */+  void write_dimacs(FILE* const fp);+++  /**+   * \copydoc AbstractGraph::write_dot(FILE *fp)+   */+  void write_dot(FILE * const fp);++  /**+   * \copydoc AbstractGraph::write_dot(const char * const file_name)+   */+  void write_dot(const char * const file_name);++  /**+   * \copydoc AbstractGraph::is_automorphism(const std::vector<unsigned int>& perm) const+   */+  bool is_automorphism(const std::vector<unsigned int>& perm) const;++++  /**+   * \copydoc AbstractGraph::get_hash()+   */ +  virtual unsigned int get_hash();++  /**+   * Return the number of vertices in the graph.+   */+  unsigned int get_nof_vertices() const {return vertices.size(); }+  +  /**+   * Add a new vertex with color 'color' in the graph and return its index.+   */+  unsigned int add_vertex(const unsigned int color = 0);++  /**+   * Add an edge from the vertex \a source to the vertex \a target.+   * Duplicate edges are ignored but try to avoid introducing+   * them in the first place as they are not ignored immediately but will+   * consume memory and computation resources for a while.+   */+  void add_edge(const unsigned int source, const unsigned int target);++  /**+   * Change the color of the vertex 'vertex' to 'color'.+   */+  void change_color(const unsigned int vertex, const unsigned int color);++  /**+   * Compare this graph with the graph \a other.+   * Returns 0 if the graphs are equal, and a negative (positive) integer+   * if this graph is "smaller than" ("greater than", resp.) than \a other.+   */+  int cmp(Digraph& other);++  /**+   * Set the splitting heuristic used by the automorphism and canonical+   * labeling algorithm.+   * The selected splitting heuristics affects the computed canonical+   * labelings; therefore, if you want to compare whether two graphs+   * are isomorphic by computing and comparing (for equality) their+   * canonical versions, be sure to use the same splitting heuristics+   * for both graphs.+   */+  void set_splitting_heuristic(SplittingHeuristic shs) {sh = shs; }++  /**+   * \copydoc AbstractGraph::permute(const unsigned int* const perm) const+   */+  Digraph* permute(const unsigned int* const perm) const;  +  Digraph* permute(const std::vector<unsigned int>& perm) const;+};+++++}++#endif
+ igraph/include/bliss/heap.hh view
@@ -0,0 +1,83 @@+#ifndef BLISS_HEAP_HH+#define BLISS_HEAP_HH++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++/** \internal+ * \brief A capacity bounded heap data structure.+ */++class Heap+{+  unsigned int N;+  unsigned int n;+  unsigned int *array;+  void upheap(unsigned int k);+  void downheap(unsigned int k);+public:+  /**+   * Create a new heap.+   * init() must be called after this.+   */+  Heap() {array = 0; n = 0; N = 0; }+  ~Heap();++  /**+   * Initialize the heap to have the capacity to hold \e size elements.+   */+  void init(const unsigned int size);++  /**+   * Is the heap empty?+   * Time complexity is O(1).+   */+  bool is_empty() const {return(n==0); }++  /**+   * Remove all the elements in the heap.+   * Time complexity is O(1).+   */+  void clear() {n = 0;}++  /**+   * Insert the element \a e in the heap.+   * Time complexity is O(log(N)), where N is the number of elements+   * currently in the heap.+   */+  void insert(const unsigned int e);++  /**+   * Remove and return the smallest element in the heap.+   * Time complexity is O(log(N)), where N is the number of elements+   * currently in the heap.+   */+  unsigned int remove();++  /**+   * Get the number of elements in the heap.+   */+  unsigned int size() const {return n; }+};++} // namespace bliss++#endif
+ igraph/include/bliss/kqueue.hh view
@@ -0,0 +1,162 @@+#ifndef BLISS_KQUEUE_HH+#define BLISS_KQUEUE_HH++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++#include "defs.hh"++namespace bliss {++/** \internal+ * \brief A very simple implementation of queues with fixed capacity.+ */++template <class Type>+class KQueue+{+public:+  /**+   * Create a new queue with capacity zero.+   * The function init() should be called next.+   */+  KQueue();++  ~KQueue();++  /**+   * Initialize the queue to have the capacity to hold at most \a N elements.+   */+  void init(const unsigned int N);+  +  /** Is the queue empty? */+  bool is_empty() const;++  /** Return the number of elements in the queue. */+  unsigned int size() const;++  /** Remove all the elements in the queue. */+  void clear();++  /** Return (but don't remove) the first element in the queue. */+  Type front() const;++  /** Remove and return the first element of the queue. */+  Type pop_front();++  /** Push the element \a e in the front of the queue. */+  void push_front(Type e);++  /** Remove and return the last element of the queue. */+  Type pop_back();++  /** Push the element \a e in the back of the queue. */+  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+{+  return *head;+}++template <class Type>+Type KQueue<Type>::pop_front()+{+  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--;+  *head = e;+}++template <class Type>+void KQueue<Type>::push_back(Type e)+{+  *tail = e;+  tail++;+  if(tail == end)+    tail = entries;+}++} // namespace bliss++#endif
+ igraph/include/bliss/kstack.hh view
@@ -0,0 +1,141 @@+#ifndef BLISS_KSTACK_H+#define BLISS_KSTACK_H++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++#include <cstdlib>+#include "defs.hh"++namespace bliss {++/** \internal+ * \brief A very simple implementation of a stack with fixed capacity.+ */+template <class Type>+class KStack {+public:+  /**+   * Create a new stack with zero capacity.+   * The function init() should be called next.+   */+  KStack();++  /**+   * Create a new stack with the capacity to hold at most \a N elements.+   */+  KStack(int N);++  ~KStack();++  /**+   * Initialize the stack to have the capacity to hold at most \a N elements.+   */+  void init(int N);++  /**+   * Is the stack empty?+   */+  bool is_empty() const {return(cursor == entries); }++  /**+   * Return (but don't remove) the top element of the stack.+   */+  Type top() const {BLISS_ASSERT(cursor > entries); return *cursor; }++  /**+   * Pop (remove) the top element of the stack.+   */+  Type pop()+  {+    return *cursor--;+  }++  /**+   * Push the element \a e in the stack.+   */+  void push(Type e)+  {+    *(++cursor) = e;+  }++  /** Remove all the elements in the stack. */+  void clean() {cursor = entries; }++  /**+   * Get the number of elements in the stack.+   */+  unsigned int size() const {return(cursor - entries); }++  /**+   * Return the i:th element in the stack, where \a i is in the range+   * 0,...,this.size()-1; the 0:th element is the bottom element+   * in the stack.+   */+  Type element_at(unsigned int i)+  {+    assert(i < size());+    return entries[i+1];+  }++  /** Return the capacity (NOT the number of elements) of the stack. */+  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);+}++} // namespace bliss++#endif
+ igraph/include/bliss/orbit.hh view
@@ -0,0 +1,111 @@+#ifndef BLISS_ORBIT_HH+#define BLISS_ORBIT_HH++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++/** \internal+ * \brief A class for representing orbit information.+ *+ * Given a set {0,...,N-1} of N elements, represent equivalence+ * classes (that is, unordered partitions) of the elements.+ * Supports only equivalence class merging, not splitting.+ * Merging two classes requires time O(k), where k is the number of+ * the elements in the smaller of the merged classes.+ * Getting the smallest representative in a class (and thus testing+ * whether two elements belong to the same class) is a constant time operation.+ */+class Orbit+{+  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:+  /**+   * Create a new orbit information object.+   * The init() function must be called next to actually initialize+   * the object.+   */+  Orbit();+  ~Orbit();++  /**+   * Initialize the orbit information to consider sets of \a N elements.+   * It is required that \a N > 0.+   * The orbit information is reset so that each element forms+   * an orbit of its own.+   * Time complexity is O(N).+   * \sa reset()+   */+  void init(const unsigned int N);++  /**+   * Reset the orbits so that each element forms an orbit of its own.+   * Time complexity is O(N).+   */+  void reset();++  /**+   * Merge the orbits of the elements \a e1 and \a e2.+   * Time complexity is O(k), where k is the number of elements in+   * the smaller of the merged orbits.+   */+  void merge_orbits(unsigned int e1, unsigned int e2);++  /**+   * Is the element \a e the smallest element in its orbit?+   * Time complexity is O(1).+   */+  bool is_minimal_representative(unsigned int e) const;++  /**+   * Get the smallest element in the orbit of the element \a e.+   * Time complexity is O(1).+   */+  unsigned int get_minimal_representative(unsigned int e) const;++  /**+   * Get the number of elements in the orbit of the element \a e.+   * Time complexity is O(1).+   */+  unsigned int orbit_size(unsigned int e) const;++  /**+   * Get the number of orbits.+   * Time complexity is O(1).+   */+  unsigned int nof_orbits() const {return _nof_orbits; }+};++} // namespace bliss++#endif
+ igraph/include/bliss/partition.hh view
@@ -0,0 +1,308 @@+#ifndef BLISS_PARTITION_HH+#define BLISS_PARTITION_HH++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {+  class Partition;+}++#include <cstdlib>+#include <cstdio>+#include <climits>+#include "kstack.hh"+#include "kqueue.hh"+#include "heap.hh"+#include "orbit.hh"+#include "graph.hh"+++namespace bliss {++/** \internal+ * \brief A class for refinable, backtrackable ordered partitions.+ *+ * This is rather a data structure with some helper functions than+ * a proper self-contained class.+ * That is, for efficiency reasons the fields of this class are directly+ * manipulated from bliss::AbstractGraph and its subclasses.+ * Conversely, some methods of this class modify the fields of+ * bliss::AbstractGraph, too.+ */+class Partition+{+public:+  /**+   * \brief Data structure for holding information about a cell in a Partition.+   */+  class Cell+  {+    friend class Partition;+  public:+    unsigned int length;+    /* Index of the first element of the cell in+       the Partition::elements array */+    unsigned int first;+    unsigned int max_ival;+    unsigned int max_ival_count;+  private:+    bool in_splitting_queue;+  public:+    bool in_neighbour_heap;+    /* Pointer to the next cell, null if this is the last one. */+    Cell* next;+    Cell* prev;+    Cell* next_nonsingleton;+    Cell* prev_nonsingleton;+    unsigned int split_level;+    /** Is this a unit cell? */+    bool is_unit() const {return(length == 1); }+    /** Is this cell in splitting queue? */+    bool is_in_splitting_queue() const {return(in_splitting_queue); }+  };+++private:++  /** \internal+   * Data structure for remembering information about splits in order to+   * perform efficient backtracking over the splits.+   */+  class RefInfo {+  public:+    unsigned int split_cell_first;+    int prev_nonsingleton_first;+    int next_nonsingleton_first;+  };+  /** \internal+   * A stack for remembering the splits, used for backtracking.+   */+  KStack<RefInfo> refinement_stack;++  class BacktrackInfo {+  public:+    unsigned int refinement_stack_size;+    unsigned int cr_backtrack_point;+  };++  /** \internal+   * The main stack for enabling backtracking.+   */+  std::vector<BacktrackInfo> bt_stack;++public:+  AbstractGraph* graph;++  /* Used during equitable partition refinement */+  KQueue<Cell*> splitting_queue;+  void  splitting_queue_add(Cell* const cell);+  Cell* splitting_queue_pop();+  bool  splitting_queue_is_empty() const;+  void  splitting_queue_clear();+++  /** Type for backtracking points. */+  typedef unsigned int BacktrackPoint;++  /**+   * Get a new backtrack point for the current partition+   */+  BacktrackPoint set_backtrack_point();++  /**+   * Backtrack to the point \a p and remove it.+   */+  void goto_backtrack_point(BacktrackPoint p);++  /**+   * Split the non-unit Cell \a cell = {\a element,e1,e2,...,en} containing+   * the element \a element in two:+   * \a cell = {e1,...,en} and \a newcell = {\a element}.+   * @param cell     a non-unit Cell+   * @param element  an element in \a cell+   * @return         the new unit Cell \a newcell+   */+  Cell* individualize(Cell* const cell,+		      const unsigned int element);++  Cell* aux_split_in_two(Cell* const cell,+			 const unsigned int first_half_size);+++private:+  unsigned int N;+  Cell* cells;+  Cell* free_cells;+  unsigned int discrete_cell_count;+public:+  Cell* first_cell;+  Cell* first_nonsingleton_cell;+  unsigned int *elements;+  /* invariant_values[e] gives the invariant value of the element e */+  unsigned int *invariant_values;+  /* element_to_cell_map[e] gives the cell of the element e */+  Cell **element_to_cell_map;+  /** Get the cell of the element \a e */+  Cell* get_cell(const unsigned int e) const {+    return element_to_cell_map[e];+  }+  /* in_pos[e] points to the elements array s.t. *in_pos[e] = e  */+  unsigned int **in_pos;++  Partition();+  ~Partition();++  /**+   * Initialize the partition to the unit partition (all elements in one cell)+   * over the \a N > 0 elements {0,...,\a N-1}.+   */+  void init(const unsigned int N);++  /**+   * Returns true iff the partition is discrete, meaning that all+   * the elements are in their own cells.+   */+  bool is_discrete() const {return(free_cells == 0); }++  unsigned int nof_discrete_cells() const {return(discrete_cell_count); }++  /**+   * Print the partition into the file stream \a fp.+   */+  size_t print(FILE* const fp, const bool add_newline = true) const;++  /**+   * Print the partition cell sizes into the file stream \a fp.+   */+  size_t print_signature(FILE* const fp, const bool add_newline = true) const;++  /*+   * Splits the Cell \a cell into [cell_1,...,cell_n]+   * according to the invariant_values of the elements in \a cell.+   * After splitting, cell_1 == \a cell.+   * Returns the pointer to the Cell cell_n;+   * cell_n != cell iff the Cell \a cell was actually splitted.+   * The flag \a max_ival_info_ok indicates whether the max_ival and+   * max_ival_count fields of the Cell \a cell have consistent values+   * when the method is called.+   * Clears the invariant values of elements in the Cell \a cell as well as+   * the max_ival and max_ival_count fields of the Cell \a cell.+   */+  Cell *zplit_cell(Cell * const cell, const bool max_ival_info_ok);++  /*+   * Routines for component recursion+   */+  void cr_init();+  void cr_free();+  unsigned int cr_get_level(const unsigned int cell_index) const;+  unsigned int cr_split_level(const unsigned int level,+			      const std::vector<unsigned int>& cells);++  /** Clear the invariant_values of the elements in the Cell \a cell. */+  void clear_ivs(Cell* const cell);++private:+  /*+   * Component recursion data structures+   */++  /* Is component recursion support in use? */+  bool cr_enabled;++  class CRCell {+  public:+    unsigned int level;+    CRCell* next;+    CRCell** prev_next_ptr;+    void detach() {+      if(next)+	next->prev_next_ptr = prev_next_ptr;+      *(prev_next_ptr) = next;+      level = UINT_MAX;+      next = 0;+      prev_next_ptr = 0;+    }+  };+  CRCell* cr_cells;+  CRCell** cr_levels;+  class CR_BTInfo {+  public:+    unsigned int created_trail_index;+    unsigned int splitted_level_trail_index;+  };+  std::vector<unsigned int> cr_created_trail;+  std::vector<unsigned int> cr_splitted_level_trail;+  std::vector<CR_BTInfo> cr_bt_info;+  unsigned int cr_max_level;+  void cr_create_at_level(const unsigned int cell_index, unsigned int level);+  void cr_create_at_level_trailed(const unsigned int cell_index, unsigned int level);+  unsigned int cr_get_backtrack_point();+  void cr_goto_backtrack_point(const unsigned int btpoint);+++  /*+   *+   * Auxiliary routines for sorting and splitting cells+   *+   */+  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);++  /*+   * Some auxiliary stuff needed for distribution count sorting.+   * To make the code thread-safe (modulo the requirement that each graph is+   * only accessed in one thread at a time), the arrays are owned by+   * the partition instance, not statically defined.+   */+  unsigned int dcs_count[256];+  unsigned int dcs_start[256];+  void dcs_cumulate_count(const unsigned int max);+};+++inline Partition::Cell*+Partition::splitting_queue_pop()+{+  Cell* const cell = splitting_queue.pop_front();+  cell->in_splitting_queue = false;+  return cell;+}++inline bool+Partition::splitting_queue_is_empty() const+{+  return splitting_queue.is_empty();+}+++inline unsigned int+Partition::cr_get_level(const unsigned int cell_index) const+{+  return(cr_cells[cell_index].level);+}++++} // namespace bliss++#endif
+ igraph/include/bliss/uintseqhash.hh view
@@ -0,0 +1,65 @@+#ifndef BLISS_UINTSEQHASH_HH+#define BLISS_UINTSEQHASH_HH++#include <cstdio>++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++/** \internal+ * \brief A hash for sequences of unsigned ints.+ */+class UintSeqHash+{+protected:+  unsigned int h;+public:+  UintSeqHash() {h = 0; }+  UintSeqHash(const UintSeqHash &other) {h = other.h; }+  UintSeqHash& operator=(const UintSeqHash &other) {h = other.h; return *this; }+  +  /** Reset the hash value. */+  void reset() {h = 0; }++  /** Add the unsigned int \a n to the sequence. */+  void update(unsigned int n);++  /** Get the hash value of the sequence seen so far. */+  unsigned int get_value() const {return h; }++  /** Compare the hash values of this and \a other.+   * Return -1/0/1 if the value of this is smaller/equal/greater than+   * that of \a other. */+  int cmp(const UintSeqHash &other) const {+    return (h < other.h)?-1:((h == other.h)?0:1);+  }+  /** An abbreviation for cmp(other) < 0 */+  bool is_lt(const UintSeqHash &other) const {return(cmp(other) < 0); }+  /** An abbreviation for cmp(other) <= 0 */+  bool is_le(const UintSeqHash &other) const {return(cmp(other) <= 0); }+  /** An abbreviation for cmp(other) == 0 */+  bool is_equal(const UintSeqHash &other) const {return(cmp(other) == 0); }+};+++} // namespace bliss++#endif
+ igraph/include/bliss/utils.hh view
@@ -0,0 +1,69 @@+#ifndef BLISS_UTILS_HH+#define BLISS_UTILS_HH++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++/**+ * \file+ * \brief Some small utilities.+ *+ */++#include <cstdio>+using namespace std;++namespace bliss {++/**+ * Print the permutation \a perm of {0,...,N-1} in the cycle format+ * in the file stream \a fp.+ * The amount \a offset is added to each element before printing,+ * e.g. the permutation (2 4) is printed as (3 5) when \a offset is 1.+ */+void print_permutation(FILE* fp,+		       const unsigned int N,+		       const unsigned int* perm,+		       const unsigned int offset = 0);++/**+ * Print the permutation \a perm of {0,...,N-1} in the cycle format+ * in the file stream \a fp.+ * The amount \a offset is added to each element before printing,+ * e.g. the permutation (2 4) is printed as (3 5) when \a offset is 1.+ */+void print_permutation(FILE* fp,+		       const std::vector<unsigned int>& perm,+		       const unsigned int offset = 0);++/**+ * Check whether \a perm is a valid permutation on {0,...,N-1}.+ * Slow, mainly for debugging and validation purposes.+ */+bool is_permutation(const unsigned int N, const unsigned int* perm);++/**+ * Check whether \a perm is a valid permutation on {0,...,N-1}.+ * Slow, mainly for debugging and validation purposes.+ */+bool is_permutation(const std::vector<unsigned int>& perm);++} // namespace bliss++#endif
+ igraph/include/cliquer/cliquer.h view
@@ -0,0 +1,57 @@++#ifndef CLIQUER_H+#define CLIQUER_H++#include <string.h>++#include "set.h"+#include "graph.h"+#include "reorder.h"++typedef struct _clique_options clique_options;+struct _clique_options {+	int *(*reorder_function)(graph_t *, boolean);+	int *reorder_map;++	/* arguments:  level, n, max, user_time, system_time, opts */+	boolean (*time_function)(int,int,int,int,double,double,+				 clique_options *);+	FILE *output;++	boolean (*user_function)(set_t,graph_t *,clique_options *);+	void *user_data;+	set_t *clique_list;+	int clique_list_length;+};++/* Weighted clique functions */+extern int clique_max_weight(graph_t *g,clique_options *opts);+extern set_t clique_find_single(graph_t *g,int min_weight,int max_weight,+				boolean maximal, clique_options *opts);+extern int clique_find_all(graph_t *g, int req_weight, boolean exact,+			   boolean maximal, clique_options *opts);++/* Unweighted clique functions */+#define clique_unweighted_max_size clique_unweighted_max_weight+extern int clique_unweighted_max_weight(graph_t *g, clique_options *opts);+extern set_t clique_unweighted_find_single(graph_t *g,int min_size,+					   int max_size,boolean maximal,+					   clique_options *opts);+extern int clique_unweighted_find_all(graph_t *g, int min_size, int max_size,+				      boolean maximal, clique_options *opts);++/* Time printing functions */+/*+extern boolean clique_print_time(int level, int i, int n, int max,+				 double cputime, double realtime,+				 clique_options *opts);+extern boolean clique_print_time_always(int level, int i, int n, int max,+					double cputime, double realtime,+					clique_options *opts);+*/++/* Alternate spelling (let's be a little forgiving): */+#define cliquer_options clique_options+#define cliquer_default_options clique_default_options++#endif /* !CLIQUER_H */
+ igraph/include/cliquer/cliquerconf.h view
@@ -0,0 +1,68 @@++#ifndef CLIQUERCONF_H+#define CLIQUERCONF_H++/*+ * setelement is the basic memory type used in sets.  It is often fastest+ * to be as large as can fit into the CPU registers.+ *+ * ELEMENTSIZE is the size of one setelement, measured in bits.  It must+ * be either 16, 32 or 64  (otherwise additional changes must be made to+ * the source).+ *+ * The default is to use "unsigned long int" and attempt to guess the+ * size using <limits.h>, which should work pretty well.  Check functioning+ * with "make test".+ */++/* typedef unsigned long int setelement; */+/* #define ELEMENTSIZE 64 */+++/*+ * INLINE is a command prepended to function declarations to instruct the+ * compiler to inline the function.  If inlining is not desired, define blank.+ *+ * The default is to use "inline", which is recognized by most compilers.+ */++/* #define INLINE */+/* #define INLINE __inline__ */+#if __STDC_VERSION__ >= 199901L+ #define INLINE inline+#else+ #if defined(_MSC_VER)+  #define INLINE __inline+ #elif defined(__GNUC__)+  #define INLINE __inline__+ #else+  #define INLINE+ #endif+#endif+++/*+ * Set handling functions are defined as static functions in set.h for+ * performance reasons.  This may cause unnecessary warnings from the+ * compiler.  Some compilers (such as GCC) have the possibility to turn+ * off the warnings on a per-function basis using a flag prepended to+ * the function declaration.+ *+ * The default is to use the correct attribute when compiling with GCC,+ * or no flag otherwise.+ */++/* #define UNUSED_FUNCTION __attribute__((unused)) */+/* #define UNUSED_FUNCTION */+++/*+ * Uncommenting the following will disable all assertions  (checks that+ * function arguments and other variables are correct).  This is highly+ * discouraged, as it allows bugs to go unnoticed easier.  The assertions+ * are set so that they do not slow down programs notably.+ */++/* #define ASSERT(x) */++#endif /* !CLIQUERCONF_H */
+ igraph/include/cliquer/graph.h view
@@ -0,0 +1,75 @@++#ifndef CLIQUER_GRAPH_H+#define CLIQUER_GRAPH_H++#include "set.h"++typedef struct _graph_t graph_t;+struct _graph_t {+	int n;             /* Vertices numbered 0...n-1 */+	set_t *edges;      /* A list of n sets (the edges). */+	int *weights;      /* A list of n vertex weights. */+};+++#define GRAPH_IS_EDGE_FAST(g,i,j)  (SET_CONTAINS_FAST((g)->edges[(i)],(j)))+#define GRAPH_IS_EDGE(g,i,j) (((i)<((g)->n))?SET_CONTAINS((g)->edges[(i)], \+							  (j)):FALSE)+#define GRAPH_ADD_EDGE(g,i,j) do {            \+	SET_ADD_ELEMENT((g)->edges[(i)],(j)); \+	SET_ADD_ELEMENT((g)->edges[(j)],(i)); \+} while (FALSE)+#define GRAPH_DEL_EDGE(g,i,j) do {            \+	SET_DEL_ELEMENT((g)->edges[(i)],(j)); \+	SET_DEL_ELEMENT((g)->edges[(j)],(i)); \+} while (FALSE)+++extern graph_t *graph_new(int n);+extern void graph_free(graph_t *g);+extern void graph_resize(graph_t *g, int size);+extern void graph_crop(graph_t *g);++extern boolean graph_weighted(graph_t *g);+extern int graph_edge_count(graph_t *g);++/*+extern graph_t *graph_read_dimacs(FILE *fp);+extern graph_t *graph_read_dimacs_file(char *file);+extern boolean graph_write_dimacs_ascii(graph_t *g, char *comment,FILE *fp);+extern boolean graph_write_dimacs_ascii_file(graph_t *g,char *comment,+					     char *file);+extern boolean graph_write_dimacs_binary(graph_t *g, char *comment,FILE *fp);+extern boolean graph_write_dimacs_binary_file(graph_t *g, char *comment,+					      char *file);+*/++extern void graph_print(graph_t *g);+extern boolean graph_test(graph_t *g, FILE *output);+extern int graph_test_regular(graph_t *g);++UNUSED_FUNCTION INLINE+static int graph_subgraph_weight(graph_t *g,set_t s) {+	int i,j;+	int count=0;+	setelement e;++	for (i=0; i<SET_ARRAY_LENGTH(s); i++) {+		if (s[i]) {+			e=s[i];+			for (j=0; j<ELEMENTSIZE; j++) {+				if (e&1)+					count+=g->weights[i*ELEMENTSIZE+j];+				e = e>>1;+			}+		}+	}+	return count;+}++UNUSED_FUNCTION INLINE+static int graph_vertex_degree(graph_t *g, int v) {+	return set_size(g->edges[v]);+}++#endif /* !CLIQUER_GRAPH_H */
+ igraph/include/cliquer/misc.h view
@@ -0,0 +1,73 @@++#ifndef CLIQUER_MISC_H+#define CLIQUER_MISC_H++#include "cliquerconf.h"++/*+ * We #define boolean instead of using a typedef because nauty.h uses it+ * also.  AFAIK, there is no way to check for an existing typedef, and+ * re-typedefing is illegal (even when using exactly the same datatype!).+ */+#ifndef boolean+#define boolean int+#endif+++/*+ * The original cliquer source has some functions incorrectly marked as unused,+ * thus leave this undefined.+ */+#define UNUSED_FUNCTION+++/*+ * Default inlining directive:  "inline"+ */+#ifndef INLINE+#define INLINE inline+#endif+++#include <stdio.h>+#include <stdlib.h>++#ifndef ASSERT+#ifdef USING_R+#include <R.h>+#define ASSERT(expr) \+        if (!(expr)) { \+	        error("cliquer file %s: line %d: assertion failed: " \+			"(%s)\n",__FILE__,__LINE__,#expr); \+	}+#else+#define ASSERT(expr) \+        if (!(expr)) { \+		fprintf(stderr,"cliquer file %s: line %d: assertion failed: " \+			"(%s)\n",__FILE__,__LINE__,#expr); \+		abort(); \+	}+#endif+#endif /* !ASSERT */+++#ifndef FALSE+#define FALSE (0)+#endif+#ifndef TRUE+#define TRUE (!FALSE)+#endif+++#ifndef MIN+#define MIN(a,b) (((a)<(b))?(a):(b))+#endif+#ifndef MAX+#define MAX(a,b) (((a)>(b))?(a):(b))+#endif+#ifndef ABS+#define ABS(v)  (((v)<0)?(-(v)):(v))+#endif++#endif /* !CLIQUER_MISC_H */+
+ igraph/include/cliquer/reorder.h view
@@ -0,0 +1,26 @@++#ifndef CLIQUER_REORDER_H+#define CLIQUER_REORDER_H++#include "set.h"+#include "graph.h"++extern void reorder_set(set_t s,int *order);+extern void reorder_graph(graph_t *g, int *order);+extern int *reorder_duplicate(int *order,int n);+extern void reorder_invert(int *order,int n);+extern void reorder_reverse(int *order,int n);+extern int *reorder_ident(int n);+extern boolean reorder_is_bijection(int *order,int n);+++#define reorder_by_default reorder_by_greedy_coloring+extern int *reorder_by_greedy_coloring(graph_t *g, boolean weighted);+extern int *reorder_by_weighted_greedy_coloring(graph_t *g, boolean weighted);+extern int *reorder_by_unweighted_greedy_coloring(graph_t *g,boolean weighted);+extern int *reorder_by_degree(graph_t *g, boolean weighted);+extern int *reorder_by_random(graph_t *g, boolean weighted);+extern int *reorder_by_ident(graph_t *g, boolean weighted);+extern int *reorder_by_reverse(graph_t *g, boolean weighted);++#endif /* !CLIQUER_REORDER_H */
+ igraph/include/cliquer/set.h view
@@ -0,0 +1,389 @@++/*+ * This file contains the set handling routines.+ *+ * Copyright (C) 2002 Sampo Niskanen, Patric Östergård.+ * Licensed under the GNU GPL, read the file LICENSE for details.+ */++#ifndef CLIQUER_SET_H+#define CLIQUER_SET_H++#include <stdio.h>+#include <stdlib.h>+#include <string.h>+#include <limits.h>+#include "misc.h"++/*+ * Sets are arrays of setelement's (typically unsigned long int's) with+ * representative bits for each value they can contain.  The values+ * are numbered 0,...,n-1.+ */+++/*** Variable types and constants. ***/+++/*+ * If setelement hasn't been declared:+ *   - use "unsigned long int" as setelement+ *   - try to deduce size from ULONG_MAX+ */++#ifndef ELEMENTSIZE+typedef unsigned long int setelement;+# if (ULONG_MAX == 65535)+#  define ELEMENTSIZE 16+# elif (ULONG_MAX == 4294967295)+#  define ELEMENTSIZE 32+# else+#  define ELEMENTSIZE 64+# endif+#endif  /* !ELEMENTSIZE */++typedef setelement * set_t;+++/*** Counting amount of 1 bits in a setelement ***/++/* Array for amount of 1 bits in a byte. */+static int set_bit_count[256] = {+	0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,+	1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,+	1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,+	2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,+	1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,+	2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,+	2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,+	3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,+	1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5,+	2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,+	2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,+	3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,+	2,3,3,4,3,4,4,5,3,4,4,5,4,5,5,6,+	3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,+	3,4,4,5,4,5,5,6,4,5,5,6,5,6,6,7,+	4,5,5,6,5,6,6,7,5,6,6,7,6,7,7,8 };++/* The following macros assume that all higher bits are 0.+ * They may in some cases be useful also on with other ELEMENTSIZE's,+ * so we define them all.  */+#define SET_ELEMENT_BIT_COUNT_8(a)  (set_bit_count[(a)])+#define SET_ELEMENT_BIT_COUNT_16(a) (set_bit_count[(a)>>8] + \+				     set_bit_count[(a)&0xFF])+#define SET_ELEMENT_BIT_COUNT_32(a) (set_bit_count[(a)>>24] + \+				     set_bit_count[((a)>>16)&0xFF] + \+				     set_bit_count[((a)>>8)&0xFF] + \+				     set_bit_count[(a)&0xFF])+#define SET_ELEMENT_BIT_COUNT_64(a) (set_bit_count[(a)>>56] + \+				     set_bit_count[((a)>>48)&0xFF] + \+				     set_bit_count[((a)>>40)&0xFF] + \+				     set_bit_count[((a)>>32)&0xFF] + \+				     set_bit_count[((a)>>24)&0xFF] + \+				     set_bit_count[((a)>>16)&0xFF] + \+				     set_bit_count[((a)>>8)&0xFF] + \+				     set_bit_count[(a)&0xFF])+#if (ELEMENTSIZE==64)+# define SET_ELEMENT_BIT_COUNT(a) SET_ELEMENT_BIT_COUNT_64(a)+# define FULL_ELEMENT ((setelement)0xFFFFFFFFFFFFFFFF)+#elif (ELEMENTSIZE==32)+# define SET_ELEMENT_BIT_COUNT(a) SET_ELEMENT_BIT_COUNT_32(a)+# define FULL_ELEMENT ((setelement)0xFFFFFFFF)+#elif (ELEMENTSIZE==16)+# define SET_ELEMENT_BIT_COUNT(a) SET_ELEMENT_BIT_COUNT_16(a)+# define FULL_ELEMENT ((setelement)0xFFFF)+#else+# error "SET_ELEMENT_BIT_COUNT(a) not defined for current ELEMENTSIZE"+#endif++++/*** Macros and functions ***/++/*+ * Gives a value with bit x (counting from lsb up) set.+ *+ * Making this as a table might speed up things on some machines+ * (though on most modern machines it's faster to shift instead of+ * using memory).  Making it a macro makes it easy to change.+ */+#define SET_BIT_MASK(x) ((setelement)1<<(x))++++/* Set element handling macros */++#define SET_ELEMENT_INTERSECT(a,b)  ((a)&(b))+#define SET_ELEMENT_UNION(a,b)      ((a)|(b))+#define SET_ELEMENT_DIFFERENCE(a,b) ((a)&(~(b)))+#define SET_ELEMENT_CONTAINS(e,v)   ((e)&SET_BIT_MASK(v))+++/* Set handling macros */++#define SET_ADD_ELEMENT(s,a) \+                       ((s)[(a)/ELEMENTSIZE] |= SET_BIT_MASK((a)%ELEMENTSIZE))+#define SET_DEL_ELEMENT(s,a) \+                       ((s)[(a)/ELEMENTSIZE] &= ~SET_BIT_MASK((a)%ELEMENTSIZE))+#define SET_CONTAINS_FAST(s,a) (SET_ELEMENT_CONTAINS((s)[(a)/ELEMENTSIZE], \+						      (a)%ELEMENTSIZE))+#define SET_CONTAINS(s,a) (((a)<SET_MAX_SIZE(s))?SET_CONTAINS_FAST(s,a):FALSE)++/* Sets can hold values between 0,...,SET_MAX_SIZE(s)-1 */+#define SET_MAX_SIZE(s) ((s)[-1])+/* Sets consist of an array of SET_ARRAY_LENGTH(s) setelements */+#define SET_ARRAY_LENGTH(s) (((s)[-1]+ELEMENTSIZE-1)/ELEMENTSIZE)+++/*+ * set_new()+ *+ * Create a new set that can hold values in the range 0,...,size-1.+ */+UNUSED_FUNCTION+static set_t set_new(int size) {+	int n;+	set_t s;++	ASSERT(size>0);++	n=(size/ELEMENTSIZE+1)+1;+	s=calloc(n,sizeof(setelement));+	s[0]=size;++	return &(s[1]);+}++/*+ * set_free()+ *+ * Free the memory associated with set s.+ */+UNUSED_FUNCTION INLINE+static void set_free(set_t s) {+	ASSERT(s!=NULL);+	free(&(s[-1]));+}++/*+ * set_resize()+ *+ * Resizes set s to given size.  If the size is less than SET_MAX_SIZE(s),+ * the last elements are dropped.+ *+ * Returns a pointer to the new set.+ */+UNUSED_FUNCTION INLINE+static set_t set_resize(set_t s, int size) {+	int n;++	ASSERT(size>0);++	n=(size/ELEMENTSIZE+1);+	s=((setelement *)realloc(s-1,(n+1)*sizeof(setelement)))+1;++	if (n>SET_ARRAY_LENGTH(s))+		memset(s+SET_ARRAY_LENGTH(s),0,+		       (n-SET_ARRAY_LENGTH(s))*sizeof(setelement));+	if (size < SET_MAX_SIZE(s))+		s[(size-1)/ELEMENTSIZE] &= (FULL_ELEMENT >>+					    (ELEMENTSIZE-size%ELEMENTSIZE));+	s[-1]=size;++	return s;+}++/*+ * set_size()+ *+ * Returns the number of elements in set s.+ */+UNUSED_FUNCTION INLINE+static int set_size(set_t s) {+	int count=0;+	setelement *c;++	for (c=s; c < s+SET_ARRAY_LENGTH(s); c++)+		count+=SET_ELEMENT_BIT_COUNT(*c);+	return count;+}++/*+ * set_duplicate()+ *+ * Returns a newly allocated duplicate of set s.+ */+UNUSED_FUNCTION INLINE+static set_t set_duplicate(set_t s) {+	set_t new;++	new=set_new(SET_MAX_SIZE(s));+	memcpy(new,s,SET_ARRAY_LENGTH(s)*sizeof(setelement));+	return new;+}++/*+ * set_copy()+ *+ * Copies set src to dest.  If dest is NULL, is equal to set_duplicate.+ * If dest smaller than src, it is freed and a new set of the same size as+ * src is returned.+ */+UNUSED_FUNCTION INLINE+static set_t set_copy(set_t dest,set_t src) {+	if (dest==NULL)+		return set_duplicate(src);+	if (SET_MAX_SIZE(dest)<SET_MAX_SIZE(src)) {+		set_free(dest);+		return set_duplicate(src);+	}+	memcpy(dest,src,SET_ARRAY_LENGTH(src)*sizeof(setelement));+	memset(dest+SET_ARRAY_LENGTH(src),0,((SET_ARRAY_LENGTH(dest) -+					      SET_ARRAY_LENGTH(src)) *+					     sizeof(setelement)));+	return dest;+}++/*+ * set_empty()+ *+ * Removes all elements from the set s.+ */+UNUSED_FUNCTION INLINE+static void set_empty(set_t s) {+	memset(s,0,SET_ARRAY_LENGTH(s)*sizeof(setelement));+	return;+}++/*+ * set_intersection()+ *+ * Store the intersection of sets a and b into res.  If res is NULL,+ * a new set is created and the result is written to it.  If res is+ * smaller than the larger one of a and b, it is freed and a new set+ * is created and the result is returned.+ *+ * Returns either res or a new set that has been allocated in its stead.+ *+ * Note:  res may not be a or b.+ */+UNUSED_FUNCTION INLINE+static set_t set_intersection(set_t res,set_t a,set_t b) {+	int i,max;++	if (res==NULL) {+		res = set_new(MAX(SET_MAX_SIZE(a),SET_MAX_SIZE(b)));+	} else if (SET_MAX_SIZE(res) < MAX(SET_MAX_SIZE(a),SET_MAX_SIZE(b))) {+		set_free(res);+		res = set_new(MAX(SET_MAX_SIZE(a),SET_MAX_SIZE(b)));+	} else {+		set_empty(res);+	}++	max=MIN(SET_ARRAY_LENGTH(a),SET_ARRAY_LENGTH(b));+	for (i=0; i<max; i++) {+		res[i]=SET_ELEMENT_INTERSECT(a[i],b[i]);+	}++	return res;+}++/*+ * set_union()+ *+ * Store the union of sets a and b into res.  If res is NULL, a new set+ * is created and the result is written to it.  If res is smaller than+ * the larger one of a and b, it is freed and a new set is created and+ * the result is returned.+ *+ * Returns either res or a new set that has been allocated in its stead.+ *+ * Note:  res may not be a or b.+ */+UNUSED_FUNCTION INLINE+static set_t set_union(set_t res,set_t a,set_t b) {+	int i,max;++	if (res==NULL) {+		res = set_new(MAX(SET_MAX_SIZE(a),SET_MAX_SIZE(b)));+	} else if (SET_MAX_SIZE(res) < MAX(SET_MAX_SIZE(a),SET_MAX_SIZE(b))) {+		set_free(res);+		res = set_new(MAX(SET_MAX_SIZE(a),SET_MAX_SIZE(b)));+	} else {+		set_empty(res);+	}++	max=MAX(SET_ARRAY_LENGTH(a),SET_ARRAY_LENGTH(b));+	for (i=0; i<max; i++) {+		res[i]=SET_ELEMENT_UNION(a[i],b[i]);+	}++	return res;+}+++/*+ * set_return_next()+ *+ * Returns the smallest value in set s which is greater than n, or -1 if+ * such a value does not exist.+ *+ * Can be used to iterate through all values of s:+ *+ * int i=-1;+ * while ((i=set_return_next(s,i))>=0) {+ *         // i is in set s+ * }+ */+UNUSED_FUNCTION INLINE+static int set_return_next(set_t s, int n) {+	if (n<0)+		n=0;+	else+		n++;+	if (n >= SET_MAX_SIZE(s))+		return -1;++	while (n%ELEMENTSIZE) {+		if (SET_CONTAINS(s,n))+			return n;+		n++;+		if (n >= SET_MAX_SIZE(s))+			return -1;+	}++	while (s[n/ELEMENTSIZE]==0) {+		n+=ELEMENTSIZE;+		if (n >= SET_MAX_SIZE(s))+			return -1;+	}+	while (!SET_CONTAINS(s,n)) {+		n++;+		if (n >= SET_MAX_SIZE(s))+			return -1;+	}+	return n;+}+++/*+ * set_print()+ *+ * Prints the size and contents of set s to stdout.+ * Mainly useful for debugging purposes and trivial output.+ */+/*+UNUSED_FUNCTION+static void set_print(set_t s) {+	int i;+	printf("size=%d(max %d)",set_size(s),(int)SET_MAX_SIZE(s));+	for (i=0; i<SET_MAX_SIZE(s); i++)+		if (SET_CONTAINS(s,i))+			printf(" %d",i);+	printf("\n");+	return;+}+*/++#endif /* !CLIQUER_SET_H */
+ igraph/include/config.h view
@@ -0,0 +1,39 @@+/* functions */+#define HAVE_EXPM1 1+#define HAVE_FABSL 1+#define HAVE_FINITE 1+#define HAVE_FMIN 1+#define HAVE_FTRUNCATE 1+#define HAVE_ISNAN 1+#define HAVE_LOG1P 1+#define HAVE_LOG2 1+#define HAVE_RINT 1+#define HAVE_RINTF 1+#define HAVE_ROUND 1+#define HAVE_SNPRINTF 1++/* libraries */+#define HAVE_MEMORY_H 1+#define HAVE_STDINT_H 1+#define HAVE_STRINGS_H 1+#define HAVE_STRING_H 1++#define IGRAPH_F77_SAVE static IGRAPH_THREAD_LOCAL+#define IGRAPH_THREAD_LOCAL ++#define INTERNAL_ARPACK 1+#define INTERNAL_BLAS 1+#define INTERNAL_F2C 1+#define INTERNAL_GLPK 1+#define INTERNAL_LAPACK 1++#define LT_OBJDIR ".libs/"+#define PACKAGE "igraph"+#define PACKAGE_BUGREPORT "igraph@igraph.org"+#define PACKAGE_NAME "igraph"+#define PACKAGE_STRING "igraph 0.8.0"+#define PACKAGE_TARNAME "igraph"+#define PACKAGE_URL ""+#define PACKAGE_VERSION "0.8.0"+#define STDC_HEADERS 1+#define VERSION "0.8.0"
+ igraph/include/cs/UFconfig.h view
@@ -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
+ igraph/include/cs/cs.h view
@@ -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
+ igraph/include/dqueue.pmt view
@@ -0,0 +1,384 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "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 */+    }+}
+ igraph/include/drl_Node.h view
@@ -0,0 +1,68 @@+/*+ * 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__
+ igraph/include/drl_Node_3d.h view
@@ -0,0 +1,68 @@+/*+ * 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__
+ igraph/include/drl_graph.h view
@@ -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
+ igraph/include/drl_graph_3d.h view
@@ -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
+ igraph/include/drl_layout.h view
@@ -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+*/
+ igraph/include/drl_layout_3d.h view
@@ -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+*/
+ igraph/include/drl_parse.h view
@@ -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
+ igraph/include/f2c.h view
@@ -0,0 +1,234 @@+/* 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
+ igraph/include/f2c/fio.h view
@@ -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)
+ igraph/include/f2c/fmt.h view
@@ -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
+ igraph/include/f2c/fp.h view
@@ -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
+ igraph/include/f2c/lio.h view
@@ -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
+ igraph/include/f2c/signal1.h view
@@ -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
+ igraph/include/f2c/sysdep1.h view
@@ -0,0 +1,76 @@+#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++#ifdef __GLIBC__+#define OFF_T __off64_t+#else+#define OFF_T off64_t+#endif /* __GLIBC__ */+#endif /* __linux__ */++#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*/
+ igraph/include/foreign-dl-header.h view
@@ -0,0 +1,42 @@+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;
+ igraph/include/foreign-dl-parser.h view
@@ -0,0 +1,107 @@+/* 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,+     ERROR = 271+   };+#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+#define ERROR 271+++++#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED+typedef union YYSTYPE+#line 86 "../../src/foreign-dl-parser.y"+{+  long int integer;+  igraph_real_t real;+}+/* Line 1529 of yacc.c.  */+#line 86 "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++
+ igraph/include/foreign-gml-header.h view
@@ -0,0 +1,30 @@+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi@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;
+ igraph/include/foreign-gml-parser.h view
@@ -0,0 +1,97 @@+/* 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,+     ERROR = 264+   };+#endif+/* Tokens.  */+#define STRING 258+#define NUM 259+#define KEYWORD 260+#define LISTOPEN 261+#define LISTCLOSE 262+#define EOFF 263+#define ERROR 264+++++#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED+typedef union YYSTYPE+#line 93 "../../src/foreign-gml-parser.y"+{+   struct {+      char *s;+      int len;+   } str;+   void *tree;+   double real;+}+/* Line 1529 of yacc.c.  */+#line 76 "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++
+ igraph/include/foreign-lgl-header.h view
@@ -0,0 +1,35 @@+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi@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;
+ igraph/include/foreign-lgl-parser.h view
@@ -0,0 +1,87 @@+/* 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,+     ERROR = 261+   };+#endif+/* Tokens.  */+#define ALNUM 258+#define NEWLINE 259+#define HASH 260+#define ERROR 261+++++#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED+typedef union YYSTYPE+#line 81 "../../src/foreign-lgl-parser.y"+{+  long int edgenum;+  double weightnum;+}+/* Line 1529 of yacc.c.  */+#line 66 "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++
+ igraph/include/foreign-ncol-header.h view
@@ -0,0 +1,34 @@+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi@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;
+ igraph/include/foreign-ncol-parser.h view
@@ -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,+     ERROR = 260+   };+#endif+/* Tokens.  */+#define ALNUM 258+#define NEWLINE 259+#define ERROR 260+++++#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED+typedef union YYSTYPE+#line 82 "../../src/foreign-ncol-parser.y"+{+  long int edgenum;+  double weightnum;+}+/* Line 1529 of yacc.c.  */+#line 64 "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++
+ igraph/include/foreign-pajek-header.h view
@@ -0,0 +1,43 @@+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi@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;
+ igraph/include/foreign-pajek-parser.h view
@@ -0,0 +1,181 @@+/* 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,+     ERROR = 270,+     VP_X_FACT = 271,+     VP_Y_FACT = 272,+     VP_IC = 273,+     VP_BC = 274,+     VP_LC = 275,+     VP_LR = 276,+     VP_LPHI = 277,+     VP_BW = 278,+     VP_FOS = 279,+     VP_PHI = 280,+     VP_R = 281,+     VP_Q = 282,+     VP_LA = 283,+     VP_FONT = 284,+     VP_URL = 285,+     VP_SIZE = 286,+     EP_C = 287,+     EP_S = 288,+     EP_A = 289,+     EP_W = 290,+     EP_H1 = 291,+     EP_H2 = 292,+     EP_A1 = 293,+     EP_A2 = 294,+     EP_K1 = 295,+     EP_K2 = 296,+     EP_AP = 297,+     EP_P = 298,+     EP_L = 299,+     EP_LP = 300,+     EP_LR = 301,+     EP_LPHI = 302,+     EP_LC = 303,+     EP_LA = 304,+     EP_SIZE = 305,+     EP_FOS = 306+   };+#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 ERROR 270+#define VP_X_FACT 271+#define VP_Y_FACT 272+#define VP_IC 273+#define VP_BC 274+#define VP_LC 275+#define VP_LR 276+#define VP_LPHI 277+#define VP_BW 278+#define VP_FOS 279+#define VP_PHI 280+#define VP_R 281+#define VP_Q 282+#define VP_LA 283+#define VP_FONT 284+#define VP_URL 285+#define VP_SIZE 286+#define EP_C 287+#define EP_S 288+#define EP_A 289+#define EP_W 290+#define EP_H1 291+#define EP_H2 292+#define EP_A1 293+#define EP_A2 294+#define EP_K1 295+#define EP_K2 296+#define EP_AP 297+#define EP_P 298+#define EP_L 299+#define EP_LP 300+#define EP_LR 301+#define EP_LPHI 302+#define EP_LC 303+#define EP_LA 304+#define EP_SIZE 305+#define EP_FOS 306+++++#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED+typedef union YYSTYPE+#line 118 "../../src/foreign-pajek-parser.y"+{+  long int intnum;+  double   realnum;  +  struct {+    char *str;+    int len;+  } string;  +}+/* Line 1529 of yacc.c.  */+#line 160 "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++
+ igraph/include/gengraph_box_list.h view
@@ -0,0 +1,89 @@+/*+ *+ * 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++#ifndef _MSC_VER+    #ifndef register+        #define register+    #endif+#endif++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
+ igraph/include/gengraph_definitions.h view
@@ -0,0 +1,216 @@+/*+ *+ * 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++#ifndef _MSC_VER+    #ifndef register+        #define register+    #endif+#endif++#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
+ igraph/include/gengraph_degree_sequence.h view
@@ -0,0 +1,101 @@+/*+ *+ * 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+
+ igraph/include/gengraph_graph_molloy_hash.h view
@@ -0,0 +1,219 @@+/*+ *+ * 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+
+ igraph/include/gengraph_graph_molloy_optimized.h view
@@ -0,0 +1,288 @@+/*+ *+ * 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++
+ igraph/include/gengraph_hash.h view
@@ -0,0 +1,308 @@+/*+ *+ * 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
+ igraph/include/gengraph_header.h view
@@ -0,0 +1,120 @@+/*+ *+ * 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
+ igraph/include/gengraph_powerlaw.h view
@@ -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/>.+ */+#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
+ igraph/include/gengraph_qsort.h view
@@ -0,0 +1,568 @@+/*+ *+ * 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>++#ifndef register+    #define register+#endif++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
+ igraph/include/gengraph_random.h view
@@ -0,0 +1,216 @@+/*+ *+ * 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+
+ igraph/include/gengraph_vertex_cover.h view
@@ -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/>.+ */+#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"++#ifndef register+    #define register+#endif++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
+ igraph/include/heap.pmt view
@@ -0,0 +1,350 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "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;+    }+}
+ igraph/include/hrg_dendro.h view
@@ -0,0 +1,316 @@+/* -*- mode: C++ -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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
+ igraph/include/hrg_graph.h view
@@ -0,0 +1,169 @@+/* -*- mode: C++ -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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
+ igraph/include/hrg_graph_simp.h view
@@ -0,0 +1,163 @@+/* -*- mode: C++ -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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"+#include "hrg_dendro.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
+ igraph/include/hrg_rbtree.h view
@@ -0,0 +1,164 @@+/* -*- mode: C++ -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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
+ igraph/include/hrg_splittree_eq.h view
@@ -0,0 +1,185 @@+/* -*- mode: C++ -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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
+ igraph/include/igraph.h view
@@ -0,0 +1,100 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#ifndef IGRAPH_H+#define IGRAPH_H++#ifndef _GNU_SOURCE+    #define _GNU_SOURCE 1+#endif++#include "igraph_version.h"+#include "igraph_memory.h"+#include "igraph_error.h"+#include "igraph_random.h"+#include "igraph_progress.h"+#include "igraph_statusbar.h"++#include "igraph_types.h"+#include "igraph_complex.h"+#include "igraph_vector.h"+#include "igraph_matrix.h"+#include "igraph_array.h"+#include "igraph_dqueue.h"+#include "igraph_stack.h"+#include "igraph_heap.h"+#include "igraph_psumtree.h"+#include "igraph_strvector.h"+#include "igraph_vector_ptr.h"+#include "igraph_spmatrix.h"+#include "igraph_sparsemat.h"+#include "igraph_qsort.h"++#include "igraph_constants.h"+#include "igraph_datatype.h"+#include "igraph_iterators.h"+#include "igraph_interface.h"+#include "igraph_constructors.h"+#include "igraph_games.h"+#include "igraph_microscopic_update.h"+#include "igraph_centrality.h"+#include "igraph_paths.h"+#include "igraph_components.h"+#include "igraph_structural.h"+#include "igraph_transitivity.h"+#include "igraph_neighborhood.h"+#include "igraph_topology.h"+#include "igraph_bipartite.h"+#include "igraph_cliques.h"+#include "igraph_layout.h"+#include "igraph_visitor.h"+#include "igraph_community.h"+#include "igraph_conversion.h"+#include "igraph_foreign.h"+#include "igraph_motifs.h"+#include "igraph_operators.h"+#include "igraph_flow.h"+#include "igraph_nongraph.h"+#include "igraph_cocitation.h"+#include "igraph_adjlist.h"+#include "igraph_attributes.h"+#include "igraph_blas.h"+#include "igraph_lapack.h"+#include "igraph_arpack.h"+#include "igraph_mixing.h"+#include "igraph_separators.h"+#include "igraph_cohesive_blocks.h"+#include "igraph_eigen.h"+#include "igraph_hrg.h"+#include "igraph_threading.h"+#include "igraph_interrupt.h"+#include "igraph_scg.h"+#include "igraph_matching.h"+#include "igraph_embedding.h"+#include "igraph_scan.h"+#include "igraph_graphlets.h"+#include "igraph_epidemics.h"+#include "igraph_lsap.h"+#include "igraph_coloring.h"++#endif
+ igraph/include/igraph_adjlist.h view
@@ -0,0 +1,232 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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;++DECLDIR int igraph_adjlist_init(const igraph_t *graph, igraph_adjlist_t *al,+                                igraph_neimode_t mode);+DECLDIR int igraph_adjlist_init_empty(igraph_adjlist_t *al, igraph_integer_t no_of_nodes);+DECLDIR igraph_integer_t igraph_adjlist_size(const igraph_adjlist_t *al);+DECLDIR int igraph_adjlist_init_complementer(const igraph_t *graph,+        igraph_adjlist_t *al,+        igraph_neimode_t mode,+        igraph_bool_t loops);+DECLDIR void igraph_adjlist_destroy(igraph_adjlist_t *al);+DECLDIR void igraph_adjlist_clear(igraph_adjlist_t *al);+DECLDIR void igraph_adjlist_sort(igraph_adjlist_t *al);+DECLDIR int igraph_adjlist_simplify(igraph_adjlist_t *al);+DECLDIR int igraph_adjlist_remove_duplicate(const igraph_t *graph,+        igraph_adjlist_t *al);+DECLDIR int igraph_adjlist_print(const igraph_adjlist_t *al);+DECLDIR int igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile);+DECLDIR igraph_bool_t igraph_adjlist_has_edge(igraph_adjlist_t* al, igraph_integer_t from, igraph_integer_t to, igraph_bool_t directed);+DECLDIR int igraph_adjlist_replace_edge(igraph_adjlist_t* al, igraph_integer_t from, igraph_integer_t oldto, igraph_integer_t newto, igraph_bool_t directed);++/* 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)])++DECLDIR int igraph_adjlist(igraph_t *graph, const igraph_adjlist_t *adjlist,+                           igraph_neimode_t mode, igraph_bool_t duplicate);++typedef struct igraph_inclist_t {+    igraph_integer_t length;+    igraph_vector_int_t *incs;+} igraph_inclist_t;++DECLDIR int igraph_inclist_init(const igraph_t *graph,+                                igraph_inclist_t *il,+                                igraph_neimode_t mode);+DECLDIR int igraph_inclist_init_empty(igraph_inclist_t *il, igraph_integer_t n);+DECLDIR void igraph_inclist_destroy(igraph_inclist_t *il);+DECLDIR void igraph_inclist_clear(igraph_inclist_t *il);+DECLDIR int igraph_inclist_remove_duplicate(const igraph_t *graph,+        igraph_inclist_t *il);+DECLDIR int igraph_inclist_print(const igraph_inclist_t *il);+DECLDIR int igraph_inclist_fprint(const igraph_inclist_t *il, FILE *outfile);++/**+ * \define igraph_inclist_get+ * Query a vector in an incidence list+ *+ * Returns a pointer to an <type>igraph_vector_int_t</type> object from an+ * incidence list containing edge ids. The vector can be modified,+ * resized, etc. as desired.+ * \param il Pointer to the incidence list.+ * \param no The vertex for which the incident edges are returned.+ * \return Pointer to an <type>igraph_vector_int_t</type> object.+ *+ * Time complexity: O(1).+ */+#define igraph_inclist_get(il,no) (&(il)->incs[(long int)(no)])++typedef struct igraph_lazy_adjlist_t {+    const igraph_t *graph;+    igraph_integer_t length;+    igraph_vector_t **adjs;+    igraph_neimode_t mode;+    igraph_lazy_adlist_simplify_t simplify;+} igraph_lazy_adjlist_t;++DECLDIR int igraph_lazy_adjlist_init(const igraph_t *graph,+                                     igraph_lazy_adjlist_t *al,+                                     igraph_neimode_t mode,+                                     igraph_lazy_adlist_simplify_t simplify);+DECLDIR void igraph_lazy_adjlist_destroy(igraph_lazy_adjlist_t *al);+DECLDIR 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)))+DECLDIR 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;++DECLDIR int igraph_lazy_inclist_init(const igraph_t *graph,+                                     igraph_lazy_inclist_t *il,+                                     igraph_neimode_t mode);+DECLDIR void igraph_lazy_inclist_destroy(igraph_lazy_inclist_t *il);+DECLDIR 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)))+DECLDIR 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;++DECLDIR int igraph_adjedgelist_init(const igraph_t *graph,+                                    igraph_inclist_t *il,+                                    igraph_neimode_t mode);+DECLDIR void igraph_adjedgelist_destroy(igraph_inclist_t *il);+DECLDIR int igraph_adjedgelist_remove_duplicate(const igraph_t *graph,+        igraph_inclist_t *il);+DECLDIR 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;++DECLDIR int igraph_lazy_adjedgelist_init(const igraph_t *graph,+        igraph_lazy_inclist_t *il,+        igraph_neimode_t mode);+DECLDIR 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)))+DECLDIR igraph_vector_t *igraph_lazy_adjedgelist_get_real(igraph_lazy_inclist_t *al,+        igraph_integer_t no);+__END_DECLS++#endif
+ igraph/include/igraph_arpack.h view
@@ -0,0 +1,333 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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++#include "igraph_decls.h"++__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 &lt;- 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;++DECLDIR void igraph_arpack_options_init(igraph_arpack_options_t *o);++DECLDIR int igraph_arpack_storage_init(igraph_arpack_storage_t *s, long int maxn,+                                       long int maxncv, long int maxldv, igraph_bool_t symm);+DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR int igraph_arpack_unpack_complex(igraph_matrix_t *vectors, igraph_matrix_t *values,+        long int nev);++__END_DECLS++#endif
+ igraph/include/igraph_arpack_internal.h view
@@ -0,0 +1,219 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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 */
+ igraph/include/igraph_array.h view
@@ -0,0 +1,61 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"++__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
+ igraph/include/igraph_array_pmt.h view
@@ -0,0 +1,51 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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);
+ igraph/include/igraph_attributes.h view
@@ -0,0 +1,873 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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 void (*igraph_function_pointer_t)(void);++typedef struct igraph_attribute_combination_record_t {+    const char *name;     /* can be NULL, meaning: the rest */+    igraph_attribute_combination_type_t type;+    igraph_function_pointer_t 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)++DECLDIR int igraph_attribute_combination_init(igraph_attribute_combination_t *comb);+DECLDIR int igraph_attribute_combination(igraph_attribute_combination_t *comb, ...);+DECLDIR void igraph_attribute_combination_destroy(igraph_attribute_combination_t *comb);+DECLDIR int igraph_attribute_combination_add(igraph_attribute_combination_t *comb,+        const char *name,+        igraph_attribute_combination_type_t type,+        igraph_function_pointer_t func);+DECLDIR int igraph_attribute_combination_remove(igraph_attribute_combination_t *comb,+        const char *name);+DECLDIR int igraph_attribute_combination_query(const igraph_attribute_combination_t *comb,+        const char *name,+        igraph_attribute_combination_type_t *type,+        igraph_function_pointer_t *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;++DECLDIR igraph_attribute_table_t * igraph_i_set_attribute_table(const igraph_attribute_table_t * table);++DECLDIR 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;++DECLDIR igraph_real_t igraph_cattribute_GAN(const igraph_t *graph, const char *name);+DECLDIR igraph_bool_t igraph_cattribute_GAB(const igraph_t *graph, const char *name);+DECLDIR const char* igraph_cattribute_GAS(const igraph_t *graph, const char *name);+DECLDIR igraph_real_t igraph_cattribute_VAN(const igraph_t *graph, const char *name,+        igraph_integer_t vid);+DECLDIR igraph_bool_t igraph_cattribute_VAB(const igraph_t *graph, const char *name,+        igraph_integer_t vid);+DECLDIR const char* igraph_cattribute_VAS(const igraph_t *graph, const char *name,+        igraph_integer_t vid);+DECLDIR igraph_real_t igraph_cattribute_EAN(const igraph_t *graph, const char *name,+        igraph_integer_t eid);+DECLDIR igraph_bool_t igraph_cattribute_EAB(const igraph_t *graph, const char *name,+        igraph_integer_t eid);+DECLDIR const char* igraph_cattribute_EAS(const igraph_t *graph, const char *name,+        igraph_integer_t eid);++DECLDIR int igraph_cattribute_VANV(const igraph_t *graph, const char *name,+                                   igraph_vs_t vids, igraph_vector_t *result);+DECLDIR int igraph_cattribute_EANV(const igraph_t *graph, const char *name,+                                   igraph_es_t eids, igraph_vector_t *result);+DECLDIR int igraph_cattribute_VASV(const igraph_t *graph, const char *name,+                                   igraph_vs_t vids, igraph_strvector_t *result);+DECLDIR int igraph_cattribute_EASV(const igraph_t *graph, const char *name,+                                   igraph_es_t eids, igraph_strvector_t *result);+DECLDIR int igraph_cattribute_VABV(const igraph_t *graph, const char *name,+                                   igraph_vs_t vids, igraph_vector_bool_t *result);+DECLDIR int igraph_cattribute_EABV(const igraph_t *graph, const char *name,+                                   igraph_es_t eids, igraph_vector_bool_t *result);++DECLDIR 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);+DECLDIR igraph_bool_t igraph_cattribute_has_attr(const igraph_t *graph,+        igraph_attribute_elemtype_t type,+        const char *name);++DECLDIR int igraph_cattribute_GAN_set(igraph_t *graph, const char *name,+                                      igraph_real_t value);+DECLDIR int igraph_cattribute_GAB_set(igraph_t *graph, const char *name,+                                      igraph_bool_t value);+DECLDIR int igraph_cattribute_GAS_set(igraph_t *graph, const char *name,+                                      const char *value);+DECLDIR int igraph_cattribute_VAN_set(igraph_t *graph, const char *name,+                                      igraph_integer_t vid, igraph_real_t value);+DECLDIR int igraph_cattribute_VAB_set(igraph_t *graph, const char *name,+                                      igraph_integer_t vid, igraph_bool_t value);+DECLDIR int igraph_cattribute_VAS_set(igraph_t *graph, const char *name,+                                      igraph_integer_t vid, const char *value);+DECLDIR int igraph_cattribute_EAN_set(igraph_t *graph, const char *name,+                                      igraph_integer_t eid, igraph_real_t value);+DECLDIR int igraph_cattribute_EAB_set(igraph_t *graph, const char *name,+                                      igraph_integer_t eid, igraph_bool_t value);+DECLDIR int igraph_cattribute_EAS_set(igraph_t *graph, const char *name,+                                      igraph_integer_t eid, const char *value);++DECLDIR int igraph_cattribute_VAN_setv(igraph_t *graph, const char *name,+                                       const igraph_vector_t *v);+DECLDIR int igraph_cattribute_VAB_setv(igraph_t *graph, const char *name,+                                       const igraph_vector_bool_t *v);+DECLDIR int igraph_cattribute_VAS_setv(igraph_t *graph, const char *name,+                                       const igraph_strvector_t *sv);+DECLDIR int igraph_cattribute_EAN_setv(igraph_t *graph, const char *name,+                                       const igraph_vector_t *v);+DECLDIR int igraph_cattribute_EAB_setv(igraph_t *graph, const char *name,+                                       const igraph_vector_bool_t *v);+DECLDIR int igraph_cattribute_EAS_setv(igraph_t *graph, const char *name,+                                       const igraph_strvector_t *sv);++DECLDIR void igraph_cattribute_remove_g(igraph_t *graph, const char *name);+DECLDIR void igraph_cattribute_remove_v(igraph_t *graph, const char *name);+DECLDIR void igraph_cattribute_remove_e(igraph_t *graph, const char *name);+DECLDIR 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
+ igraph/include/igraph_bipartite.h view
@@ -0,0 +1,97 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_vector.h"+#include "igraph_matrix.h"+#include "igraph_datatype.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Bipartite networks                                 */+/* -------------------------------------------------- */++DECLDIR 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);++DECLDIR int igraph_create_bipartite(igraph_t *g, const igraph_vector_bool_t *types,+                                    const igraph_vector_t *edges,+                                    igraph_bool_t directed);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR int igraph_is_bipartite(const igraph_t *graph,+                                igraph_bool_t *res,+                                igraph_vector_bool_t *type);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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
+ igraph/include/igraph_blas.h view
@@ -0,0 +1,65 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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"+#include "igraph_decls.h"++__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>+ */++DECLDIR 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);+DECLDIR 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);++DECLDIR igraph_real_t igraph_blas_dnrm2(const igraph_vector_t *v);++__END_DECLS++#endif
+ igraph/include/igraph_blas_internal.h view
@@ -0,0 +1,65 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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 igraphdgemm_    dgemm_+    #define igraphdgemv_    dgemv_+    #define igraphddot_ ddot_+    #define igraphdnrm2_    dnrm2_+    #define igraphlsame_    lsame_+    #define igraphdrot_     drot_+    #define igraphidamax_   idamax_+    #define igraphdtrmm_    dtrmm_+    #define igraphdasum_    dasum_+    #define igraphdtrsm_    dtrsm_+    #define igraphdtrsv_    dtrsv_+    #define igraphdnrm2_    dnrm2_+#endif++int igraphdgemv_(char *trans, int *m, int *n, igraph_real_t *alpha,+                 igraph_real_t *a, int *lda, igraph_real_t *x, int *incx,+                 igraph_real_t *beta, igraph_real_t *y, int *incy);++int igraphdgemm_(char *transa, char *transb, int *m, int *n, int *k,+                 double *alpha, double *a, int *lda, double *b, int *ldb,+                 double *beta, double *c__, int *ldc);++double igraphdnrm2_(int *n, double *x, int *incx);++#endif
+ igraph/include/igraph_centrality.h view
@@ -0,0 +1,212 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_datatype.h"+#include "igraph_iterators.h"+#include "igraph_arpack.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Centrality                                         */+/* -------------------------------------------------- */++DECLDIR 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);+DECLDIR 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);++DECLDIR 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);+DECLDIR 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);+DECLDIR int igraph_edge_betweenness(const igraph_t *graph, igraph_vector_t *result,+                                    igraph_bool_t directed,+                                    const igraph_vector_t *weigths);+DECLDIR 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);+DECLDIR 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;++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR 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);++DECLDIR 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);+DECLDIR 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);++DECLDIR int igraph_constraint(const igraph_t *graph, igraph_vector_t *res,+                              igraph_vs_t vids, const igraph_vector_t *weights);++DECLDIR 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);++DECLDIR int igraph_convergence_degree(const igraph_t *graph, igraph_vector_t *result,+                                      igraph_vector_t *ins, igraph_vector_t *outs);++DECLDIR 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);++DECLDIR igraph_real_t igraph_centralization(const igraph_vector_t *scores,+        igraph_real_t theoretical_max,+        igraph_bool_t normalized);++DECLDIR 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);+DECLDIR 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);++DECLDIR 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);+DECLDIR int igraph_centralization_betweenness_tmax(const igraph_t *graph,+        igraph_integer_t nodes,+        igraph_bool_t directed,+        igraph_real_t *res);++DECLDIR 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);+DECLDIR int igraph_centralization_closeness_tmax(const igraph_t *graph,+        igraph_integer_t nodes,+        igraph_neimode_t mode,+        igraph_real_t *res);++DECLDIR 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);+DECLDIR 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
+ igraph/include/igraph_cliquer.h view
@@ -0,0 +1,29 @@+#ifndef IGRAPH_CLIQUER_H+#define IGRAPH_CLIQUER_H++#include "igraph_types_internal.h"+#include "igraph_interface.h"+#include "igraph_cliques.h"++int igraph_i_cliquer_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,+                             igraph_integer_t min_size, igraph_integer_t max_size);++int igraph_i_cliquer_histogram(const igraph_t *graph, igraph_vector_t *hist,+                               igraph_integer_t min_size, igraph_integer_t max_size);++int igraph_i_cliquer_callback(const igraph_t *graph,+                              igraph_integer_t min_size, igraph_integer_t max_size,+                              igraph_clique_handler_t *cliquehandler_fn, void *arg);++int igraph_i_weighted_cliques(const igraph_t *graph,+                              const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res,+                              igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal);++int igraph_i_largest_weighted_cliques(const igraph_t *graph,+                                      const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res);++int igraph_i_weighted_clique_number(const igraph_t *graph,+                                    const igraph_vector_t *vertex_weights, igraph_real_t *res);++#endif // IGRAPH_CLIQUER_H+
+ igraph/include/igraph_cliques.h view
@@ -0,0 +1,114 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_types.h"+#include "igraph_datatype.h"+#include "igraph_vector_ptr.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Cliques, maximal independent vertex sets           */+/* -------------------------------------------------- */++DECLDIR int igraph_maximal_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,+                                   igraph_integer_t min_size, igraph_integer_t max_size);+DECLDIR int igraph_maximal_cliques_file(const igraph_t *graph,+                                        FILE *outfile,+                                        igraph_integer_t min_size,+                                        igraph_integer_t max_size);+DECLDIR int igraph_maximal_cliques_count(const igraph_t *graph,+        igraph_integer_t *res,+        igraph_integer_t min_size,+        igraph_integer_t max_size);+DECLDIR 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);+DECLDIR int igraph_maximal_cliques_hist(const igraph_t *graph,+                                        igraph_vector_t *hist,+                                        igraph_integer_t min_size,+                                        igraph_integer_t max_size);++DECLDIR int igraph_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,+                           igraph_integer_t min_size, igraph_integer_t max_size);+DECLDIR int igraph_clique_size_hist(const igraph_t *graph, igraph_vector_t *hist,+                                    igraph_integer_t min_size, igraph_integer_t max_size);+DECLDIR int igraph_largest_cliques(const igraph_t *graph,+                                   igraph_vector_ptr_t *cliques);+DECLDIR int igraph_clique_number(const igraph_t *graph, igraph_integer_t *no);+DECLDIR int igraph_weighted_cliques(const igraph_t *graph,+                                    const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res,+                                    igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal);+DECLDIR int igraph_largest_weighted_cliques(const igraph_t *graph,+        const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res);+DECLDIR int igraph_weighted_clique_number(const igraph_t *graph,+        const igraph_vector_t *vertex_weights, igraph_real_t *res);+DECLDIR int igraph_independent_vertex_sets(const igraph_t *graph,+        igraph_vector_ptr_t *res,+        igraph_integer_t min_size,+        igraph_integer_t max_size);+DECLDIR int igraph_largest_independent_vertex_sets(const igraph_t *graph,+        igraph_vector_ptr_t *res);+DECLDIR int igraph_maximal_independent_vertex_sets(const igraph_t *graph,+        igraph_vector_ptr_t *res);+DECLDIR int igraph_independence_number(const igraph_t *graph, igraph_integer_t *no);++/**+ * \typedef igraph_clique_handler_t+ * \brief Type of clique handler functions+ *+ * Callback type, called when a clique was found.+ *+ * See the details at the documentation of \ref+ * igraph_cliques_callback().+ *+ * \param clique The current clique. Destroying and freeing+ *   this vector is left to the user.+ *   Use \ref igraph_vector_destroy() and \ref igraph_free()+ *   to do this.+ * \param arg This extra argument was passed to \ref+ *   igraph_cliques_callback() when it was called.+ * \return Boolean, whether to continue with the clique search.+ */+typedef igraph_bool_t igraph_clique_handler_t(igraph_vector_t *clique, void *arg);++DECLDIR int igraph_cliques_callback(const igraph_t *graph,+                                    igraph_integer_t min_size, igraph_integer_t max_size,+                                    igraph_clique_handler_t *cliquehandler_fn, void *arg);++DECLDIR int igraph_maximal_cliques_callback(const igraph_t *graph,+        igraph_clique_handler_t *cliquehandler_fn, void *arg,+        igraph_integer_t min_size, igraph_integer_t max_size);+++__END_DECLS++#endif
+ igraph/include/igraph_cocitation.h view
@@ -0,0 +1,66 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_types.h"+#include "igraph_matrix.h"+#include "igraph_datatype.h"+#include "igraph_iterators.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Cocitation and other similarity measures           */+/* -------------------------------------------------- */++DECLDIR int igraph_cocitation(const igraph_t *graph, igraph_matrix_t *res,+                              const igraph_vs_t vids);+DECLDIR int igraph_bibcoupling(const igraph_t *graph, igraph_matrix_t *res,+                               const igraph_vs_t vids);++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR 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
+ igraph/include/igraph_cohesive_blocks.h view
@@ -0,0 +1,41 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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"++__BEGIN_DECLS++DECLDIR 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);++__END_DECLS++#endif
+ igraph/include/igraph_coloring.h view
@@ -0,0 +1,23 @@+#ifndef IGRAPH_COLORING_H+#define IGRAPH_COLORING_H++#include "igraph_datatype.h"++__BEGIN_DECLS++/**+ * \typedef igraph_coloring_greedy_t+ * Ordering heuristics for igraph_vertex_coloring_greedy+ *+ * \enumval IGRAPH_COLORING_GREEDY_COLORED_NEIGHBORS  Choose vertex with largest number of already colored neighbors.+ *+ */+typedef enum {+    IGRAPH_COLORING_GREEDY_COLORED_NEIGHBORS = 0+} igraph_coloring_greedy_t;++DECLDIR int igraph_vertex_coloring_greedy(const igraph_t *graph, igraph_vector_int_t *colors, igraph_coloring_greedy_t heuristic);++__END_DECLS++#endif /* IGRAPH_COLORING_H */
+ igraph/include/igraph_community.h view
@@ -0,0 +1,247 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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                                            */+/* -------------------------------------------------- */++DECLDIR 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:  */++DECLDIR int igraph_community_optimal_modularity(const igraph_t *graph,+        igraph_real_t *modularity,+        igraph_vector_t *membership,+        const igraph_vector_t *weights);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);+DECLDIR 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);++DECLDIR 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);++DECLDIR 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);+DECLDIR int igraph_le_community_to_membership(const igraph_matrix_t *merges,+        igraph_integer_t steps,+        igraph_vector_t *membership,+        igraph_vector_t *csize);++DECLDIR int igraph_modularity(const igraph_t *graph,+                              const igraph_vector_t *membership,+                              igraph_real_t *modularity,+                              const igraph_vector_t *weights);++DECLDIR int igraph_modularity_matrix(const igraph_t *graph,+                                     igraph_matrix_t *modmat,+                                     const igraph_vector_t *weights);++DECLDIR int igraph_reindex_membership(igraph_vector_t *membership,+                                      igraph_vector_t *new_to_old,+                                      igraph_integer_t *nb_clusters);++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);++DECLDIR 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);++DECLDIR int igraph_community_fluid_communities(const igraph_t *graph,+        igraph_integer_t no_of_communities,+        igraph_vector_t *membership,+        igraph_real_t *modularity);++DECLDIR 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);++DECLDIR 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);++DECLDIR int igraph_community_leiden(const igraph_t *graph,+                                    const igraph_vector_t *edge_weights,+                                    const igraph_vector_t *node_weights,+                                    const igraph_real_t resolution_parameter,+                                    const igraph_real_t beta,+                                    const igraph_bool_t start,+                                    igraph_vector_t *membership,+                                    igraph_integer_t *nb_clusters,+                                    igraph_real_t *quality);+/* -------------------------------------------------- */+/* Community Structure Comparison                     */+/* -------------------------------------------------- */++DECLDIR int igraph_compare_communities(const igraph_vector_t *comm1,+                                       const igraph_vector_t *comm2,+                                       igraph_real_t* result,+                                       igraph_community_comparison_t method);+DECLDIR 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
+ igraph/include/igraph_complex.h view
@@ -0,0 +1,104 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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])++DECLDIR igraph_complex_t igraph_complex(igraph_real_t x, igraph_real_t y);+DECLDIR igraph_complex_t igraph_complex_polar(igraph_real_t r, igraph_real_t theta);++DECLDIR igraph_bool_t igraph_complex_eq_tol(igraph_complex_t z1,+        igraph_complex_t z2,+        igraph_real_t tol);++DECLDIR igraph_real_t igraph_complex_mod(igraph_complex_t z);+DECLDIR igraph_real_t igraph_complex_arg(igraph_complex_t z);++DECLDIR igraph_real_t igraph_complex_abs(igraph_complex_t z);+DECLDIR igraph_real_t igraph_complex_logabs(igraph_complex_t z);++DECLDIR igraph_complex_t igraph_complex_add(igraph_complex_t z1,+        igraph_complex_t z2);+DECLDIR igraph_complex_t igraph_complex_sub(igraph_complex_t z1,+        igraph_complex_t z2);+DECLDIR igraph_complex_t igraph_complex_mul(igraph_complex_t z1,+        igraph_complex_t z2);+DECLDIR igraph_complex_t igraph_complex_div(igraph_complex_t z1,+        igraph_complex_t z2);++DECLDIR igraph_complex_t igraph_complex_add_real(igraph_complex_t z,+        igraph_real_t x);+DECLDIR igraph_complex_t igraph_complex_add_imag(igraph_complex_t z,+        igraph_real_t y);+DECLDIR igraph_complex_t igraph_complex_sub_real(igraph_complex_t z,+        igraph_real_t x);+DECLDIR igraph_complex_t igraph_complex_sub_imag(igraph_complex_t z,+        igraph_real_t y);+DECLDIR igraph_complex_t igraph_complex_mul_real(igraph_complex_t z,+        igraph_real_t x);+DECLDIR igraph_complex_t igraph_complex_mul_imag(igraph_complex_t z,+        igraph_real_t y);+DECLDIR igraph_complex_t igraph_complex_div_real(igraph_complex_t z,+        igraph_real_t x);+DECLDIR igraph_complex_t igraph_complex_div_imag(igraph_complex_t z,+        igraph_real_t y);++DECLDIR igraph_complex_t igraph_complex_conj(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_neg(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_inv(igraph_complex_t z);++DECLDIR igraph_complex_t igraph_complex_sqrt(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_sqrt_real(igraph_real_t x);+DECLDIR igraph_complex_t igraph_complex_exp(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_pow(igraph_complex_t z1,+        igraph_complex_t z2);+DECLDIR igraph_complex_t igraph_complex_pow_real(igraph_complex_t z,+        igraph_real_t x);+DECLDIR igraph_complex_t igraph_complex_log(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_log10(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_log_b(igraph_complex_t z,+        igraph_complex_t b);++DECLDIR igraph_complex_t igraph_complex_sin(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_cos(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_tan(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_sec(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_csc(igraph_complex_t z);+DECLDIR igraph_complex_t igraph_complex_cot(igraph_complex_t z);++__END_DECLS++#endif
+ igraph/include/igraph_components.h view
@@ -0,0 +1,61 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_vector.h"+#include "igraph_vector_ptr.h"+#include "igraph_datatype.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Components                                         */+/* -------------------------------------------------- */++DECLDIR int igraph_clusters(const igraph_t *graph, igraph_vector_t *membership,+                            igraph_vector_t *csize, igraph_integer_t *no,+                            igraph_connectedness_t mode);+DECLDIR int igraph_is_connected(const igraph_t *graph, igraph_bool_t *res,+                                igraph_connectedness_t mode);+DECLDIR void igraph_decompose_destroy(igraph_vector_ptr_t *complist);+DECLDIR int igraph_decompose(const igraph_t *graph, igraph_vector_ptr_t *components,+                             igraph_connectedness_t mode,+                             long int maxcompno, long int minelements);+DECLDIR int igraph_articulation_points(const igraph_t *graph,+                                       igraph_vector_t *res);+DECLDIR 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);+DECLDIR int igraph_bridges(const igraph_t *graph, igraph_vector_t *bridges);++__END_DECLS++#endif
+ igraph/include/igraph_constants.h view
@@ -0,0 +1,193 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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_SIMPLE_NO_MULTIPLE_UNIFORM+             } igraph_degseq_t;++typedef enum { IGRAPH_REALIZE_DEGSEQ_SMALLEST = 0,+               IGRAPH_REALIZE_DEGSEQ_LARGEST,+               IGRAPH_REALIZE_DEGSEQ_INDEX+             } igraph_realize_degseq_t;++typedef enum { IGRAPH_RANDOM_TREE_PRUFER = 0,+               IGRAPH_RANDOM_TREE_LERW+             } igraph_random_tree_t;++typedef enum { IGRAPH_FILEFORMAT_EDGELIST = 0,+               IGRAPH_FILEFORMAT_NCOL,+               IGRAPH_FILEFORMAT_PAJEK,+               IGRAPH_FILEFORMAT_LGL,+               IGRAPH_FILEFORMAT_GRAPHML+             } igraph_fileformat_type_t;++typedef enum { IGRAPH_REWIRING_SIMPLE = 0,+               IGRAPH_REWIRING_SIMPLE_LOOPS+             } igraph_rewiring_t;++typedef enum { IGRAPH_EDGEORDER_ID = 0,+               IGRAPH_EDGEORDER_FROM,+               IGRAPH_EDGEORDER_TO+             } igraph_edgeorder_type_t;++typedef enum { IGRAPH_TO_DIRECTED_ARBITRARY = 0,+               IGRAPH_TO_DIRECTED_MUTUAL+             } igraph_to_directed_t;++typedef enum { IGRAPH_TO_UNDIRECTED_EACH = 0,+               IGRAPH_TO_UNDIRECTED_COLLAPSE,+               IGRAPH_TO_UNDIRECTED_MUTUAL+             } igraph_to_undirected_t;++typedef enum { IGRAPH_VCONN_NEI_ERROR = 0,+               IGRAPH_VCONN_NEI_NUMBER_OF_NODES,+               IGRAPH_VCONN_NEI_IGNORE,+               IGRAPH_VCONN_NEI_NEGATIVE+             } igraph_vconn_nei_t;++typedef enum { IGRAPH_SPINCOMM_UPDATE_SIMPLE = 0,+               IGRAPH_SPINCOMM_UPDATE_CONFIG+             } igraph_spincomm_update_t;++typedef enum { IGRAPH_DONT_SIMPLIFY = 0,+               IGRAPH_SIMPLIFY+             } igraph_lazy_adlist_simplify_t;++typedef enum { IGRAPH_TRANSITIVITY_NAN = 0,+               IGRAPH_TRANSITIVITY_ZERO+             } igraph_transitivity_mode_t;++typedef enum { IGRAPH_SPINCOMM_IMP_ORIG = 0,+               IGRAPH_SPINCOMM_IMP_NEG+             } igraph_spinglass_implementation_t;++typedef enum { IGRAPH_COMMCMP_VI = 0,+               IGRAPH_COMMCMP_NMI,+               IGRAPH_COMMCMP_SPLIT_JOIN,+               IGRAPH_COMMCMP_RAND,+               IGRAPH_COMMCMP_ADJUSTED_RAND+             } igraph_community_comparison_t;++typedef enum { IGRAPH_ADD_WEIGHTS_NO = 0,+               IGRAPH_ADD_WEIGHTS_YES,+               IGRAPH_ADD_WEIGHTS_IF_PRESENT+             } igraph_add_weights_t;++typedef enum { IGRAPH_BARABASI_BAG = 0,+               IGRAPH_BARABASI_PSUMTREE,+               IGRAPH_BARABASI_PSUMTREE_MULTIPLE+             } igraph_barabasi_algorithm_t;++typedef enum { IGRAPH_FAS_EXACT_IP = 0,+               IGRAPH_FAS_APPROX_EADES+             } igraph_fas_algorithm_t;++typedef enum { IGRAPH_SUBGRAPH_AUTO = 0,+               IGRAPH_SUBGRAPH_COPY_AND_DELETE,+               IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH+             } igraph_subgraph_implementation_t;++typedef enum { IGRAPH_IMITATE_AUGMENTED = 0,+               IGRAPH_IMITATE_BLIND,+               IGRAPH_IMITATE_CONTRACTED+             } igraph_imitate_algorithm_t;++typedef igraph_real_t  igraph_scalar_function_t(const igraph_vector_t *var,+        const igraph_vector_t *par,+        void* extra);+typedef void igraph_vector_function_t(const igraph_vector_t *var,+                                      const igraph_vector_t *par,+                                      igraph_vector_t* res, void* extra);++typedef enum { IGRAPH_LAYOUT_GRID = 0,+               IGRAPH_LAYOUT_NOGRID,+               IGRAPH_LAYOUT_AUTOGRID+             } igraph_layout_grid_t;++typedef enum { IGRAPH_RANDOM_WALK_STUCK_ERROR = 0,+               IGRAPH_RANDOM_WALK_STUCK_RETURN+             } igraph_random_walk_stuck_t;+++__END_DECLS++#endif
+ igraph/include/igraph_constructors.h view
@@ -0,0 +1,80 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_matrix.h"+#include "igraph_datatype.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Constructors, deterministic                        */+/* -------------------------------------------------- */++DECLDIR int igraph_create(igraph_t *graph, const igraph_vector_t *edges, igraph_integer_t n,+                          igraph_bool_t directed);+DECLDIR int igraph_small(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed,+                         ...);+DECLDIR int igraph_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,+                             igraph_adjacency_t mode);+DECLDIR int igraph_weighted_adjacency(igraph_t *graph, igraph_matrix_t *adjmatrix,+                                      igraph_adjacency_t mode, const char* attr,+                                      igraph_bool_t loops);+DECLDIR int igraph_star(igraph_t *graph, igraph_integer_t n, igraph_star_mode_t mode,+                        igraph_integer_t center);+DECLDIR 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);+DECLDIR int igraph_ring(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed,+                        igraph_bool_t mutual, igraph_bool_t circular);+DECLDIR int igraph_tree(igraph_t *graph, igraph_integer_t n, igraph_integer_t children,+                        igraph_tree_mode_t type);+DECLDIR int igraph_from_prufer(igraph_t *graph, const igraph_vector_int_t *prufer);+DECLDIR int igraph_full(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, igraph_bool_t loops);+DECLDIR int igraph_full_citation(igraph_t *graph, igraph_integer_t n,+                                 igraph_bool_t directed);+DECLDIR int igraph_atlas(igraph_t *graph, int number);+DECLDIR int igraph_extended_chordal_ring(igraph_t *graph, igraph_integer_t nodes,+        const igraph_matrix_t *W, igraph_bool_t directed);+DECLDIR int igraph_connect_neighborhood(igraph_t *graph, igraph_integer_t order,+                                        igraph_neimode_t mode);+DECLDIR int igraph_linegraph(const igraph_t *graph, igraph_t *linegraph);++DECLDIR int igraph_de_bruijn(igraph_t *graph, igraph_integer_t m, igraph_integer_t n);+DECLDIR int igraph_kautz(igraph_t *graph, igraph_integer_t m, igraph_integer_t n);+DECLDIR int igraph_famous(igraph_t *graph, const char *name);+DECLDIR int igraph_lcf_vector(igraph_t *graph, igraph_integer_t n,+                              const igraph_vector_t *shifts,+                              igraph_integer_t repeats);+DECLDIR int igraph_lcf(igraph_t *graph, igraph_integer_t n, ...);+DECLDIR int igraph_realize_degree_sequence(igraph_t *graph,+        const igraph_vector_t *outdeg, const igraph_vector_t *indeg,+        igraph_realize_degseq_t method);++__END_DECLS++#endif
+ igraph/include/igraph_conversion.h view
@@ -0,0 +1,66 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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                                         */+/* -------------------------------------------------- */++DECLDIR int igraph_get_adjacency(const igraph_t *graph, igraph_matrix_t *res,+                                 igraph_get_adjacency_t type, igraph_bool_t eids);+DECLDIR int igraph_get_adjacency_sparse(const igraph_t *graph, igraph_spmatrix_t *res,+                                        igraph_get_adjacency_t type);++DECLDIR int igraph_get_stochastic(const igraph_t *graph,+                                  igraph_matrix_t *matrix,+                                  igraph_bool_t column_wise);++DECLDIR int igraph_get_stochastic_sparsemat(const igraph_t *graph,+        igraph_sparsemat_t *sparsemat,+        igraph_bool_t column_wise);++DECLDIR int igraph_get_edgelist(const igraph_t *graph, igraph_vector_t *res, igraph_bool_t bycol);++DECLDIR int igraph_to_directed(igraph_t *graph,+                               igraph_to_directed_t flags);+DECLDIR int igraph_to_undirected(igraph_t *graph,+                                 igraph_to_undirected_t flags,+                                 const igraph_attribute_combination_t *edge_comb);+DECLDIR int igraph_to_prufer(const igraph_t *graph, igraph_vector_int_t *prufer);++__END_DECLS++#endif
+ igraph/include/igraph_datatype.h view
@@ -0,0 +1,83 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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
+ igraph/include/igraph_decls.h view
@@ -0,0 +1,26 @@+#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++#undef DECLDIR+#if defined (_WIN32) || defined (WIN32) || defined (_WIN64) || defined (WIN64)+    #if defined (__MINGW32__) || defined (__CYGWIN32__)+        #define DECLDIR /**/+    #else+        #ifdef IGRAPH_EXPORTS+            #define DECLDIR __declspec(dllexport)+        #elif defined(IGRAPH_STATIC)+            #define DECLDIR /**/+        #else+            #define DECLDIR __declspec(dllimport)+        #endif+    #endif+#else+    #define DECLDIR /**/+#endif
+ igraph/include/igraph_dqueue.h view
@@ -0,0 +1,73 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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"+#include "igraph_decls.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* double ended queue, very useful                    */+/* -------------------------------------------------- */++#define BASE_IGRAPH_REAL+#include "igraph_pmt.h"+#include "igraph_dqueue_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_IGRAPH_REAL++#define BASE_LONG+#include "igraph_pmt.h"+#include "igraph_dqueue_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_LONG++#define BASE_CHAR+#include "igraph_pmt.h"+#include "igraph_dqueue_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_CHAR++#define BASE_BOOL+#include "igraph_pmt.h"+#include "igraph_dqueue_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_BOOL++#define BASE_INT+#include "igraph_pmt.h"+#include "igraph_dqueue_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_INT++#define IGRAPH_DQUEUE_NULL { 0,0,0,0 }+#define IGRAPH_DQUEUE_INIT_FINALLY(v, size) \+    do { IGRAPH_CHECK(igraph_dqueue_init(v, size)); \+        IGRAPH_FINALLY(igraph_dqueue_destroy, v); } while (0)++__END_DECLS++#endif
+ igraph/include/igraph_dqueue_pmt.h view
@@ -0,0 +1,49 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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);++DECLDIR int FUNCTION(igraph_dqueue, init)    (TYPE(igraph_dqueue)* q, long int size);+DECLDIR void FUNCTION(igraph_dqueue, destroy) (TYPE(igraph_dqueue)* q);+DECLDIR igraph_bool_t FUNCTION(igraph_dqueue, empty)   (const TYPE(igraph_dqueue)* q);+DECLDIR void FUNCTION(igraph_dqueue, clear)   (TYPE(igraph_dqueue)* q);+DECLDIR igraph_bool_t FUNCTION(igraph_dqueue, full)    (TYPE(igraph_dqueue)* q);+DECLDIR long int FUNCTION(igraph_dqueue, size)    (const TYPE(igraph_dqueue)* q);+DECLDIR BASE FUNCTION(igraph_dqueue, pop)     (TYPE(igraph_dqueue)* q);+DECLDIR BASE FUNCTION(igraph_dqueue, pop_back)(TYPE(igraph_dqueue)* q);+DECLDIR BASE FUNCTION(igraph_dqueue, head)    (const TYPE(igraph_dqueue)* q);+DECLDIR BASE FUNCTION(igraph_dqueue, back)    (const TYPE(igraph_dqueue)* q);+DECLDIR int FUNCTION(igraph_dqueue, push)    (TYPE(igraph_dqueue)* q, BASE elem);+int FUNCTION(igraph_dqueue, print)(const TYPE(igraph_dqueue)* q);+int FUNCTION(igraph_dqueue, fprint)(const TYPE(igraph_dqueue)* q, FILE *file);+DECLDIR BASE FUNCTION(igraph_dqueue, e)(const TYPE(igraph_dqueue) *q, long int idx);
+ igraph/include/igraph_eigen.h view
@@ -0,0 +1,112 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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++#include "igraph_decls.h"++__BEGIN_DECLS++typedef enum { IGRAPH_EIGEN_AUTO = 0,+               IGRAPH_EIGEN_LAPACK,+               IGRAPH_EIGEN_ARPACK,+               IGRAPH_EIGEN_COMP_AUTO,+               IGRAPH_EIGEN_COMP_LAPACK,+               IGRAPH_EIGEN_COMP_ARPACK+             } igraph_eigen_algorithm_t;++typedef enum { IGRAPH_EIGEN_LM = 0,+               IGRAPH_EIGEN_SM, /* 1 */+               IGRAPH_EIGEN_LA, /* 2 */+               IGRAPH_EIGEN_SA, /* 3 */+               IGRAPH_EIGEN_BE, /* 4 */+               IGRAPH_EIGEN_LR, /* 5 */+               IGRAPH_EIGEN_SR, /* 6 */+               IGRAPH_EIGEN_LI, /* 7 */+               IGRAPH_EIGEN_SI, /* 8 */+               IGRAPH_EIGEN_ALL, /* 9 */+               IGRAPH_EIGEN_INTERVAL, /* 10 */+               IGRAPH_EIGEN_SELECT+             }  /* 11 */+igraph_eigen_which_position_t;++typedef struct igraph_eigen_which_t {+    igraph_eigen_which_position_t pos;+    int howmany;+    int il, iu;+    igraph_real_t vl, vu;+    int vestimate;+    igraph_lapack_dgeevx_balance_t balance;+} igraph_eigen_which_t;++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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
+ igraph/include/igraph_embedding.h view
@@ -0,0 +1,69 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#ifndef IGRAPH_EMBEDDING_H+#define IGRAPH_EMBEDDING_H++#include "igraph_decls.h"+#include "igraph_datatype.h"+#include "igraph_arpack.h"+#include "igraph_eigen.h"+#include "igraph_constants.h"++__BEGIN_DECLS++DECLDIR int igraph_adjacency_spectral_embedding(const igraph_t *graph,+        igraph_integer_t no,+        const igraph_vector_t *weights,+        igraph_eigen_which_position_t which,+        igraph_bool_t scaled,+        igraph_matrix_t *X,+        igraph_matrix_t *Y,+        igraph_vector_t *D,+        const igraph_vector_t *cvec,+        igraph_arpack_options_t *options);++typedef enum {+    IGRAPH_EMBEDDING_D_A = 0,+    IGRAPH_EMBEDDING_I_DAD,+    IGRAPH_EMBEDDING_DAD,+    IGRAPH_EMBEDDING_OAP+} igraph_laplacian_spectral_embedding_type_t;++DECLDIR int igraph_laplacian_spectral_embedding(const igraph_t *graph,+        igraph_integer_t no,+        const igraph_vector_t *weights,+        igraph_eigen_which_position_t which,+        igraph_neimode_t degmode,+        igraph_laplacian_spectral_embedding_type_t type,+        igraph_bool_t scaled,+        igraph_matrix_t *X,+        igraph_matrix_t *Y,+        igraph_vector_t *D,+        igraph_arpack_options_t *options);++DECLDIR int igraph_dim_select(const igraph_vector_t *sv, igraph_integer_t *dim);++__END_DECLS++#endif
+ igraph/include/igraph_epidemics.h view
@@ -0,0 +1,66 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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;++DECLDIR int igraph_sir_init(igraph_sir_t *sir);+DECLDIR void igraph_sir_destroy(igraph_sir_t *sir);++DECLDIR 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
+ igraph/include/igraph_error.h view
@@ -0,0 +1,720 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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>++#include "igraph_decls.h"++__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.+ */++DECLDIR igraph_error_handler_t* igraph_set_error_handler(igraph_error_handler_t* new_handler);++/**+ * \typedef igraph_error_type_t+ * \brief Error code type.+ * These are the possible values returned by \a igraph functions.+ * Note that these are interesting only if you defined an error handler+ * with \ref igraph_set_error_handler(). Otherwise the program is aborted+ * and the function causing the error never returns.+ *+ * \enumval IGRAPH_SUCCESS The function successfully completed its task.+ * \enumval IGRAPH_FAILURE Something went wrong. You'll almost never+ *    meet this error as normally more specific error codes are used.+ * \enumval IGRAPH_ENOMEM There wasn't enough memory to allocate+ *    on the heap.+ * \enumval IGRAPH_PARSEERROR A parse error was found in a file.+ * \enumval IGRAPH_EINVAL A parameter's value is invalid. Eg. negative+ *    number was specified as the number of vertices.+ * \enumval IGRAPH_EXISTS A graph/vertex/edge attribute is already+ *    installed with the given name.+ * \enumval IGRAPH_EINVEVECTOR Invalid vector of vertex ids. A vertex id+ *    is either negative or bigger than the number of vertices minus one.+ * \enumval IGRAPH_EINVVID Invalid vertex id, negative or too big.+ * \enumval IGRAPH_NONSQUARE A non-square matrix was received while a+ *    square matrix was expected.+ * \enumval IGRAPH_EINVMODE Invalid mode parameter.+ * \enumval IGRAPH_EFILE A file operation failed. Eg. a file doesn't exist,+ *   or the user has no rights to open it.+ * \enumval IGRAPH_UNIMPLEMENTED Attempted to call an unimplemented or+ *   disabled (at compile-time) function.+ * \enumval IGRAPH_DIVERGED A numeric algorithm failed to converge.+ * \enumval IGRAPH_ARPACK_PROD Matrix-vector product failed.+ * \enumval IGRAPH_ARPACK_NPOS N must be positive.+ * \enumval IGRAPH_ARPACK_NEVNPOS NEV must be positive.+ * \enumval IGRAPH_ARPACK_NCVSMALL NCV must be bigger.+ * \enumval IGRAPH_ARPACK_NONPOSI Maximum number of iterations should be positive.+ * \enumval IGRAPH_ARPACK_WHICHINV Invalid WHICH parameter.+ * \enumval IGRAPH_ARPACK_BMATINV Invalid BMAT parameter.+ * \enumval IGRAPH_ARPACK_WORKLSMALL WORKL is too small.+ * \enumval IGRAPH_ARPACK_TRIDERR LAPACK error in tridiagonal eigenvalue calculation.+ * \enumval IGRAPH_ARPACK_ZEROSTART Starting vector is zero.+ * \enumval IGRAPH_ARPACK_MODEINV MODE is invalid.+ * \enumval IGRAPH_ARPACK_MODEBMAT MODE and BMAT are not compatible.+ * \enumval IGRAPH_ARPACK_ISHIFT ISHIFT must be 0 or 1.+ * \enumval IGRAPH_ARPACK_NEVBE NEV and WHICH='BE' are incompatible.+ * \enumval IGRAPH_ARPACK_NOFACT Could not build an Arnoldi factorization.+ * \enumval IGRAPH_ARPACK_FAILED No eigenvalues to sufficient accuracy.+ * \enumval IGRAPH_ARPACK_HOWMNY HOWMNY is invalid.+ * \enumval IGRAPH_ARPACK_HOWMNYS HOWMNY='S' is not implemented.+ * \enumval IGRAPH_ARPACK_EVDIFF Different number of converged Ritz values.+ * \enumval IGRAPH_ARPACK_SHUR Error from calculation of a real Schur form.+ * \enumval IGRAPH_ARPACK_LAPACK LAPACK (dtrevc) error for calculating eigenvectors.+ * \enumval IGRAPH_ARPACK_UNKNOWN Unknown ARPACK error.+ * \enumval IGRAPH_ENEGLOOP Negative loop detected while calculating shortest paths.+ * \enumval IGRAPH_EINTERNAL Internal error, likely a bug in igraph.+ * \enumval IGRAPH_EDIVZERO Big integer division by zero.+ * \enumval IGARPH_GLP_EBOUND GLPK error (GLP_EBOUND).+ * \enumval IGARPH_GLP_EROOT GLPK error (GLP_EROOT).+ * \enumval IGARPH_GLP_ENOPFS GLPK error (GLP_ENOPFS).+ * \enumval IGARPH_GLP_ENODFS GLPK error (GLP_ENODFS).+ * \enumval IGARPH_GLP_EFAIL GLPK error (GLP_EFAIL).+ * \enumval IGARPH_GLP_EMIPGAP GLPK error (GLP_EMIPGAP).+ * \enumval IGARPH_GLP_ETMLIM GLPK error (GLP_ETMLIM).+ * \enumval IGARPH_GLP_ESTOP GLPK error (GLP_ESTOP).+ * \enumval IGRAPH_EATTRIBUTES Attribute handler error. The user is not+ *   expected to find this; it is signalled if some igraph function is+ *   not using the attribute handler interface properly.+ * \enumval IGRAPH_EATTRCOMBINE Unimplemented attribute combination+ *   method for the given attribute type.+ * \enumval IGRAPH_ELAPACK A LAPACK call resulted an error.+ * \enumval IGRAPH_EDRL Internal error in the DrL layout generator.+ * \enumval IGRAPH_EOVERFLOW Integer or double overflow.+ * \enumval IGRAPH_EGLP Internal GLPK error.+ * \enumval IGRAPH_CPUTIME CPU time exceeded.+ * \enumval IGRAPH_EUNDERFLOW Integer or double underflow.+ * \enumval IGRAPH_ERWSTUCK Random walk got stuck.+ */++/* Each enum value below must have a corresponding error string in+ * igraph_i_error_strings[] in igraph_error.c */+typedef enum {+    IGRAPH_SUCCESS           = 0,+    IGRAPH_FAILURE           = 1,+    IGRAPH_ENOMEM            = 2,+    IGRAPH_PARSEERROR        = 3,+    IGRAPH_EINVAL            = 4,+    IGRAPH_EXISTS            = 5,+    IGRAPH_EINVEVECTOR       = 6,+    IGRAPH_EINVVID           = 7,+    IGRAPH_NONSQUARE         = 8,+    IGRAPH_EINVMODE          = 9,+    IGRAPH_EFILE             = 10,+    IGRAPH_UNIMPLEMENTED     = 12,+    IGRAPH_INTERRUPTED       = 13,+    IGRAPH_DIVERGED          = 14,+    IGRAPH_ARPACK_PROD       = 15,+    IGRAPH_ARPACK_NPOS       = 16,+    IGRAPH_ARPACK_NEVNPOS    = 17,+    IGRAPH_ARPACK_NCVSMALL   = 18,+    IGRAPH_ARPACK_NONPOSI    = 19,+    IGRAPH_ARPACK_WHICHINV   = 20,+    IGRAPH_ARPACK_BMATINV    = 21,+    IGRAPH_ARPACK_WORKLSMALL = 22,+    IGRAPH_ARPACK_TRIDERR    = 23,+    IGRAPH_ARPACK_ZEROSTART  = 24,+    IGRAPH_ARPACK_MODEINV    = 25,+    IGRAPH_ARPACK_MODEBMAT   = 26,+    IGRAPH_ARPACK_ISHIFT     = 27,+    IGRAPH_ARPACK_NEVBE      = 28,+    IGRAPH_ARPACK_NOFACT     = 29,+    IGRAPH_ARPACK_FAILED     = 30,+    IGRAPH_ARPACK_HOWMNY     = 31,+    IGRAPH_ARPACK_HOWMNYS    = 32,+    IGRAPH_ARPACK_EVDIFF     = 33,+    IGRAPH_ARPACK_SHUR       = 34,+    IGRAPH_ARPACK_LAPACK     = 35,+    IGRAPH_ARPACK_UNKNOWN    = 36,+    IGRAPH_ENEGLOOP          = 37,+    IGRAPH_EINTERNAL         = 38,+    IGRAPH_ARPACK_MAXIT      = 39,+    IGRAPH_ARPACK_NOSHIFT    = 40,+    IGRAPH_ARPACK_REORDER    = 41,+    IGRAPH_EDIVZERO          = 42,+    IGRAPH_GLP_EBOUND        = 43,+    IGRAPH_GLP_EROOT         = 44,+    IGRAPH_GLP_ENOPFS        = 45,+    IGRAPH_GLP_ENODFS        = 46,+    IGRAPH_GLP_EFAIL         = 47,+    IGRAPH_GLP_EMIPGAP       = 48,+    IGRAPH_GLP_ETMLIM        = 49,+    IGRAPH_GLP_ESTOP         = 50,+    IGRAPH_EATTRIBUTES       = 51,+    IGRAPH_EATTRCOMBINE      = 52,+    IGRAPH_ELAPACK           = 53,+    IGRAPH_EDRL              = 54,+    IGRAPH_EOVERFLOW         = 55,+    IGRAPH_EGLP              = 56,+    IGRAPH_CPUTIME           = 57,+    IGRAPH_EUNDERFLOW        = 58,+    IGRAPH_ERWSTUCK          = 59,+    IGRAPH_STOP              = 60, /* undocumented, used internally; signals a request to stop in functions like igraph_i_maximal_cliques_bk */+} 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().+ */++DECLDIR 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().+ */++DECLDIR int igraph_errorf(const char *reason, const char *file, int line,+                          int igraph_errno, ...);++DECLDIR 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.+ */++DECLDIR 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*);++DECLDIR 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.+ */++DECLDIR 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.+ */++DECLDIR 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.+ */+DECLDIR 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(GCC_VERSION_MAJOR) && defined(__GNUC__)+    #define GCC_VERSION_MAJOR  __GNUC__+#endif++#if defined(GCC_VERSION_MAJOR) && (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(&amp;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.+ */++DECLDIR igraph_warning_handler_t* igraph_set_warning_handler(igraph_warning_handler_t* new_handler);++extern igraph_warning_handler_t igraph_warning_handler_ignore;+extern igraph_warning_handler_t igraph_warning_handler_print;++/**+ * \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.+ */++DECLDIR 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.+ */++DECLDIR 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
+ igraph/include/igraph_estack.h view
@@ -0,0 +1,47 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/igraph_flow.h view
@@ -0,0 +1,169 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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;++DECLDIR 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);+DECLDIR 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);++DECLDIR 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);+DECLDIR 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);++DECLDIR int igraph_mincut_value(const igraph_t *graph, igraph_real_t *res,+                                const igraph_vector_t *capacity);+DECLDIR 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);++DECLDIR 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);+DECLDIR int igraph_vertex_connectivity(const igraph_t *graph, igraph_integer_t *res,+                                       igraph_bool_t checks);++DECLDIR int igraph_st_edge_connectivity(const igraph_t *graph, igraph_integer_t *res,+                                        igraph_integer_t source,+                                        igraph_integer_t target);+DECLDIR int igraph_edge_connectivity(const igraph_t *graph, igraph_integer_t *res,+                                     igraph_bool_t checks);++DECLDIR int igraph_edge_disjoint_paths(const igraph_t *graph, igraph_integer_t *res,+                                       igraph_integer_t source,+                                       igraph_integer_t target);+DECLDIR int igraph_vertex_disjoint_paths(const igraph_t *graph, igraph_integer_t *res,+        igraph_integer_t source,+        igraph_integer_t target);++DECLDIR int igraph_adhesion(const igraph_t *graph, igraph_integer_t *res,+                            igraph_bool_t checks);+DECLDIR int igraph_cohesion(const igraph_t *graph, igraph_integer_t *res,+                            igraph_bool_t checks);++/* s-t cut listing related stuff */++DECLDIR int igraph_even_tarjan_reduction(const igraph_t *graph, igraph_t *graphbar,+        igraph_vector_t *capacity);++DECLDIR 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);+DECLDIR int igraph_reverse_residual_graph(const igraph_t *graph,+        const igraph_vector_t *capacity,+        igraph_t *residual,+        const igraph_vector_t *flow);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR int igraph_gomory_hu_tree(const igraph_t *graph,+                                  igraph_t *tree,+                                  igraph_vector_t *flows,+                                  const igraph_vector_t *capacity);++__END_DECLS++#endif
+ igraph/include/igraph_flow_internal.h view
@@ -0,0 +1,42 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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"+#include "igraph_datatype.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+
+ igraph/include/igraph_foreign.h view
@@ -0,0 +1,85 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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                     */+/* -------------------------------------------------- */++DECLDIR int igraph_read_graph_edgelist(igraph_t *graph, FILE *instream,+                                       igraph_integer_t n, igraph_bool_t directed);+DECLDIR 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);+DECLDIR int igraph_read_graph_lgl(igraph_t *graph, FILE *instream,+                                  igraph_bool_t names, igraph_add_weights_t weights,+                                  igraph_bool_t directed);+DECLDIR int igraph_read_graph_pajek(igraph_t *graph, FILE *instream);+DECLDIR int igraph_read_graph_graphml(igraph_t *graph, FILE *instream,+                                      int index);+DECLDIR 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);+DECLDIR int igraph_read_graph_graphdb(igraph_t *graph, FILE *instream,+                                      igraph_bool_t directed);+DECLDIR int igraph_read_graph_gml(igraph_t *graph, FILE *instream);+DECLDIR int igraph_read_graph_dl(igraph_t *graph, FILE *instream,+                                 igraph_bool_t directed);++DECLDIR int igraph_write_graph_edgelist(const igraph_t *graph, FILE *outstream);+DECLDIR int igraph_write_graph_ncol(const igraph_t *graph, FILE *outstream,+                                    const char *names, const char *weights);+DECLDIR int igraph_write_graph_lgl(const igraph_t *graph, FILE *outstream,+                                   const char *names, const char *weights,+                                   igraph_bool_t isolates);+DECLDIR int igraph_write_graph_graphml(const igraph_t *graph, FILE *outstream,+                                       igraph_bool_t prefixattr);+DECLDIR int igraph_write_graph_pajek(const igraph_t *graph, FILE *outstream);+DECLDIR int igraph_write_graph_dimacs(const igraph_t *graph, FILE *outstream,+                                      long int source, long int target,+                                      const igraph_vector_t *capacity);+DECLDIR int igraph_write_graph_gml(const igraph_t *graph, FILE *outstream,+                                   const igraph_vector_t *id, const char *creator);+DECLDIR int igraph_write_graph_dot(const igraph_t *graph, FILE *outstream);+DECLDIR int igraph_write_graph_leda(const igraph_t *graph, FILE *outstream,+                                    const char* vertex_attr_name, const char* edge_attr_name);++__END_DECLS++#endif
+ igraph/include/igraph_games.h view
@@ -0,0 +1,227 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_matrix.h"+#include "igraph_vector.h"+#include "igraph_datatype.h"+#include "igraph_vector_ptr.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Constructors, games (=stochastic)                  */+/* -------------------------------------------------- */++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR int igraph_degree_sequence_game(igraph_t *graph, const igraph_vector_t *out_deg,+                                        const igraph_vector_t *in_deg,+                                        igraph_degseq_t method);+DECLDIR int igraph_growing_random_game(igraph_t *graph, igraph_integer_t n,+                                       igraph_integer_t m, igraph_bool_t directed, igraph_bool_t citation);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR int igraph_rewire_edges(igraph_t *graph, igraph_real_t prob,+                                igraph_bool_t loops, igraph_bool_t multiple);+DECLDIR int igraph_rewire_directed_edges(igraph_t *graph, igraph_real_t prob,+        igraph_bool_t loops, igraph_neimode_t mode);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);+++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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);++DECLDIR int igraph_hsbm_game(igraph_t *graph, igraph_integer_t n,+                             igraph_integer_t m, const igraph_vector_t *rho,+                             const igraph_matrix_t *C, igraph_real_t p);++DECLDIR int igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n,+                                  const igraph_vector_int_t *mlist,+                                  const igraph_vector_ptr_t *rholist,+                                  const igraph_vector_ptr_t *Clist,+                                  igraph_real_t p);++DECLDIR int igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_graph,+                                   igraph_real_t corr, igraph_real_t p,+                                   const igraph_vector_t *permutation);++DECLDIR int igraph_correlated_pair_game(igraph_t *graph1, igraph_t *graph2,+                                        int n, igraph_real_t corr, igraph_real_t p,+                                        igraph_bool_t directed,+                                        const igraph_vector_t *permutation);++DECLDIR int igraph_tree_game(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed,+                             igraph_random_tree_t method);++DECLDIR int igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs,+                                    igraph_bool_t directed);++DECLDIR int igraph_sample_sphere_surface(igraph_integer_t dim, igraph_integer_t n,+        igraph_real_t radius,+        igraph_bool_t positive,+        igraph_matrix_t *res);++DECLDIR int igraph_sample_sphere_volume(igraph_integer_t dim, igraph_integer_t n,+                                        igraph_real_t radius,+                                        igraph_bool_t positive,+                                        igraph_matrix_t *res);++DECLDIR int igraph_sample_dirichlet(igraph_integer_t n, const igraph_vector_t *alpha,+                                    igraph_matrix_t *res);++__END_DECLS++#endif
+ igraph/include/igraph_glpk_support.h view
@@ -0,0 +1,48 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/igraph_gml_tree.h view
@@ -0,0 +1,91 @@+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_types.h"+#include "igraph_vector.h"+#include "igraph_vector_ptr.h"++__BEGIN_DECLS++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);++__END_DECLS++#endif
+ igraph/include/igraph_graphlets.h view
@@ -0,0 +1,52 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_datatype.h"+#include "igraph_vector_ptr.h"+#include "igraph_interface.h"++__BEGIN_DECLS++DECLDIR int igraph_graphlets_candidate_basis(const igraph_t *graph,+        const igraph_vector_t *weights,+        igraph_vector_ptr_t *cliques,+        igraph_vector_t *thresholds);++DECLDIR 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);++DECLDIR 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
+ igraph/include/igraph_hacks_internal.h view
@@ -0,0 +1,57 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/igraph_heap.h view
@@ -0,0 +1,83 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"++__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
+ igraph/include/igraph_heap_pmt.h view
@@ -0,0 +1,45 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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);++DECLDIR int FUNCTION(igraph_heap, init)(TYPE(igraph_heap)* h, long int size);+DECLDIR int FUNCTION(igraph_heap, init_array)(TYPE(igraph_heap) *t, BASE* data, long int len);+DECLDIR void FUNCTION(igraph_heap, destroy)(TYPE(igraph_heap)* h);+DECLDIR igraph_bool_t FUNCTION(igraph_heap, empty)(TYPE(igraph_heap)* h);+DECLDIR int FUNCTION(igraph_heap, push)(TYPE(igraph_heap)* h, BASE elem);+DECLDIR BASE FUNCTION(igraph_heap, top)(TYPE(igraph_heap)* h);+DECLDIR BASE FUNCTION(igraph_heap, delete_top)(TYPE(igraph_heap)* h);+DECLDIR long int FUNCTION(igraph_heap, size)(TYPE(igraph_heap)* h);+DECLDIR int FUNCTION(igraph_heap, reserve)(TYPE(igraph_heap)* h, long int size);++void FUNCTION(igraph_heap, i_build)(BASE* arr, long int size, long int head);+void FUNCTION(igraph_heap, i_shift_up)(BASE* arr, long int size, long int elem);+void FUNCTION(igraph_heap, i_sink)(BASE* arr, long int size, long int head);+void FUNCTION(igraph_heap, i_switch)(BASE* arr, long int e1, long int e2);+
+ igraph/include/igraph_hrg.h view
@@ -0,0 +1,114 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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;++DECLDIR int igraph_hrg_init(igraph_hrg_t *hrg, int n);+DECLDIR void igraph_hrg_destroy(igraph_hrg_t *hrg);+DECLDIR int igraph_hrg_size(const igraph_hrg_t *hrg);+DECLDIR int igraph_hrg_resize(igraph_hrg_t *hrg, int newsize);++DECLDIR int igraph_hrg_fit(const igraph_t *graph,+                           igraph_hrg_t *hrg,+                           igraph_bool_t start,+                           int steps);++DECLDIR int igraph_hrg_sample(const igraph_t *graph,+                              igraph_t *sample,+                              igraph_vector_ptr_t *samples,+                              igraph_hrg_t *hrg,+                              igraph_bool_t start);++DECLDIR int igraph_hrg_game(igraph_t *graph,+                            const igraph_hrg_t *hrg);++DECLDIR int igraph_hrg_dendrogram(igraph_t *graph,+                                  const igraph_hrg_t *hrg);++DECLDIR 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);++DECLDIR 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);++DECLDIR int igraph_hrg_create(igraph_hrg_t *hrg,+                              const igraph_t *graph,+                              const igraph_vector_t *prob);++__END_DECLS++#endif  /* IGRAPH_HRG_H */
+ igraph/include/igraph_interface.h view
@@ -0,0 +1,86 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_types.h"+#include "igraph_datatype.h"+#include "igraph_iterators.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Interface                                          */+/* -------------------------------------------------- */++DECLDIR int igraph_empty(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed);+DECLDIR int igraph_empty_attrs(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, void *attr);+DECLDIR void igraph_destroy(igraph_t *graph);+DECLDIR int igraph_copy(igraph_t *to, const igraph_t *from);+DECLDIR int igraph_add_edges(igraph_t *graph, const igraph_vector_t *edges,+                             void *attr);+DECLDIR int igraph_add_vertices(igraph_t *graph, igraph_integer_t nv,+                                void *attr);+DECLDIR int igraph_delete_edges(igraph_t *graph, igraph_es_t edges);+DECLDIR int igraph_delete_vertices(igraph_t *graph, const igraph_vs_t vertices);+DECLDIR int igraph_delete_vertices_idx(igraph_t *graph, const igraph_vs_t vertices,+                                       igraph_vector_t *idx,+                                       igraph_vector_t *invidx);+DECLDIR igraph_integer_t igraph_vcount(const igraph_t *graph);+DECLDIR igraph_integer_t igraph_ecount(const igraph_t *graph);+DECLDIR int igraph_neighbors(const igraph_t *graph, igraph_vector_t *neis, igraph_integer_t vid,+                             igraph_neimode_t mode);+DECLDIR igraph_bool_t igraph_is_directed(const igraph_t *graph);+DECLDIR int igraph_degree(const igraph_t *graph, igraph_vector_t *res,+                          const igraph_vs_t vids, igraph_neimode_t mode,+                          igraph_bool_t loops);+DECLDIR int igraph_edge(const igraph_t *graph, igraph_integer_t eid,+                        igraph_integer_t *from, igraph_integer_t *to);+DECLDIR int igraph_edges(const igraph_t *graph, igraph_es_t eids,+                         igraph_vector_t *edges);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR int igraph_adjacent(const igraph_t *graph, igraph_vector_t *eids, igraph_integer_t vid,+                            igraph_neimode_t mode);          /* deprecated */+DECLDIR int igraph_incident(const igraph_t *graph, igraph_vector_t *eids, igraph_integer_t vid,+                            igraph_neimode_t mode);++#define IGRAPH_FROM(g,e) ((igraph_integer_t)(VECTOR((g)->from)[(long int)(e)]))+#define IGRAPH_TO(g,e)   ((igraph_integer_t)(VECTOR((g)->to)  [(long int)(e)]))+#define IGRAPH_OTHER(g,e,v) \+    ((igraph_integer_t)(IGRAPH_TO(g,(e))==(v) ? IGRAPH_FROM((g),(e)) : IGRAPH_TO((g),(e))))++__END_DECLS++#endif
+ igraph/include/igraph_interrupt.h view
@@ -0,0 +1,128 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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"+#include "igraph_decls.h"++__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.+ */++DECLDIR int igraph_allow_interruption(void* data);++DECLDIR igraph_interruption_handler_t * igraph_set_interruption_handler (igraph_interruption_handler_t * new_handler);++__END_DECLS++#endif
+ igraph/include/igraph_interrupt_internal.h view
@@ -0,0 +1,69 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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+
+ igraph/include/igraph_iterators.h view
@@ -0,0 +1,401 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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;++DECLDIR int igraph_vs_all(igraph_vs_t *vs);+DECLDIR igraph_vs_t igraph_vss_all(void);++DECLDIR int igraph_vs_adj(igraph_vs_t *vs,+                          igraph_integer_t vid, igraph_neimode_t mode);+DECLDIR igraph_vs_t igraph_vss_adj(igraph_integer_t vid, igraph_neimode_t mode);++DECLDIR int igraph_vs_nonadj(igraph_vs_t *vs, igraph_integer_t vid,+                             igraph_neimode_t mode);++DECLDIR int igraph_vs_none(igraph_vs_t *vs);+DECLDIR igraph_vs_t igraph_vss_none(void);++DECLDIR int igraph_vs_1(igraph_vs_t *vs, igraph_integer_t vid);+DECLDIR igraph_vs_t igraph_vss_1(igraph_integer_t vid);++DECLDIR int igraph_vs_vector(igraph_vs_t *vs,+                             const igraph_vector_t *v);+DECLDIR igraph_vs_t igraph_vss_vector(const igraph_vector_t *v);++DECLDIR int igraph_vs_vector_small(igraph_vs_t *vs, ...);++DECLDIR int igraph_vs_vector_copy(igraph_vs_t *vs,+                                  const igraph_vector_t *v);++DECLDIR int igraph_vs_seq(igraph_vs_t *vs, igraph_integer_t from, igraph_integer_t to);+DECLDIR igraph_vs_t igraph_vss_seq(igraph_integer_t from, igraph_integer_t to);++DECLDIR void igraph_vs_destroy(igraph_vs_t *vs);++DECLDIR igraph_bool_t igraph_vs_is_all(const igraph_vs_t *vs);++DECLDIR int igraph_vs_copy(igraph_vs_t* dest, const igraph_vs_t* src);++DECLDIR int igraph_vs_as_vector(const igraph_t *graph, igraph_vs_t vs,+                                igraph_vector_t *v);+DECLDIR int igraph_vs_size(const igraph_t *graph, const igraph_vs_t *vs,+                           igraph_integer_t *result);+DECLDIR 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(&amp;vs, 0, IGRAPH_ALL);+ * igraph_vit_create(&amp;graph, vs, &amp;vit);+ * while (!IGRAPH_VIT_END(vit)) {+ *   printf(" %li", (long int) IGRAPH_VIT_GET(vit));+ *   IGRAPH_VIT_NEXT(vit);+ * }+ * printf("\n");+ * ...+ * igraph_vit_destroy(&amp;vit);+ * igraph_vs_destroy(&amp;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]))++DECLDIR int igraph_vit_create(const igraph_t *graph,+                              igraph_vs_t vs, igraph_vit_t *vit);+DECLDIR void igraph_vit_destroy(const igraph_vit_t *vit);++DECLDIR 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;++DECLDIR int igraph_es_all(igraph_es_t *es,+                          igraph_edgeorder_type_t order);+DECLDIR igraph_es_t igraph_ess_all(igraph_edgeorder_type_t order);++DECLDIR int igraph_es_adj(igraph_es_t *es,+                          igraph_integer_t vid, igraph_neimode_t mode);     /* deprecated */+DECLDIR int igraph_es_incident(igraph_es_t *es,+                               igraph_integer_t vid, igraph_neimode_t mode);++DECLDIR int igraph_es_none(igraph_es_t *es);+DECLDIR igraph_es_t igraph_ess_none(void);++DECLDIR int igraph_es_1(igraph_es_t *es, igraph_integer_t eid);+DECLDIR igraph_es_t igraph_ess_1(igraph_integer_t eid);++DECLDIR int igraph_es_vector(igraph_es_t *es,+                             const igraph_vector_t *v);+DECLDIR igraph_es_t igraph_ess_vector(const igraph_vector_t *v);++DECLDIR int igraph_es_fromto(igraph_es_t *es,+                             igraph_vs_t from, igraph_vs_t to);++DECLDIR int igraph_es_seq(igraph_es_t *es, igraph_integer_t from, igraph_integer_t to);+DECLDIR igraph_es_t igraph_ess_seq(igraph_integer_t from, igraph_integer_t to);++DECLDIR int igraph_es_vector_copy(igraph_es_t *es, const igraph_vector_t *v);++DECLDIR int igraph_es_pairs(igraph_es_t *es, const igraph_vector_t *v,+                            igraph_bool_t directed);+DECLDIR int igraph_es_pairs_small(igraph_es_t *es, igraph_bool_t directed, ...);++DECLDIR int igraph_es_multipairs(igraph_es_t *es, const igraph_vector_t *v,+                                 igraph_bool_t directed);++DECLDIR int igraph_es_path(igraph_es_t *es, const igraph_vector_t *v,+                           igraph_bool_t directed);+DECLDIR int igraph_es_path_small(igraph_es_t *es, igraph_bool_t directed, ...);++DECLDIR void igraph_es_destroy(igraph_es_t *es);++DECLDIR igraph_bool_t igraph_es_is_all(const igraph_es_t *es);++DECLDIR int igraph_es_copy(igraph_es_t* dest, const igraph_es_t* src);++DECLDIR int igraph_es_as_vector(const igraph_t *graph, igraph_es_t es,+                                igraph_vector_t *v);+DECLDIR int igraph_es_size(const igraph_t *graph, const igraph_es_t *es,+                           igraph_integer_t *result);+DECLDIR 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]))++DECLDIR int igraph_eit_create(const igraph_t *graph,+                              igraph_es_t es, igraph_eit_t *eit);+DECLDIR void igraph_eit_destroy(const igraph_eit_t *eit);++DECLDIR int igraph_eit_as_vector(const igraph_eit_t *eit, igraph_vector_t *v);++__END_DECLS++#endif
+ igraph/include/igraph_lapack.h view
@@ -0,0 +1,114 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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_LAPACK_H+#define IGRAPH_LAPACK_H++#include "igraph_vector.h"+#include "igraph_matrix.h"+#include "igraph_decls.h"++__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>+ */++DECLDIR int igraph_lapack_dgetrf(igraph_matrix_t *a, igraph_vector_int_t *ipiv,+                                 int *info);+DECLDIR int igraph_lapack_dgetrs(igraph_bool_t transpose, const igraph_matrix_t *a,+                                 igraph_vector_int_t *ipiv, igraph_matrix_t *b);+DECLDIR 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;++DECLDIR 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? */++DECLDIR 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;++DECLDIR 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);++DECLDIR int igraph_lapack_dgehrd(const igraph_matrix_t *A,+                                 int ilo, int ihi,+                                 igraph_matrix_t *result);++DECLDIR int igraph_lapack_ddot(const igraph_vector_t *v1, const igraph_vector_t *v2,+                               igraph_real_t *res);++__END_DECLS++#endif
+ igraph/include/igraph_lapack_internal.h view
@@ -0,0 +1,184 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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 igraphdsyrk_    dsyrk_+    #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 igraphdpotrf_   dpotrf_+    #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_+    #define igraphddot_     ddot_+#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);++igraph_real_t igraphddot_(int *n, igraph_real_t *dx, int *incx,+                          igraph_real_t *dy, int *incy);++#endif
+ igraph/include/igraph_layout.h view
@@ -0,0 +1,250 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_vector.h"+#include "igraph_vector_ptr.h"+#include "igraph_matrix.h"+#include "igraph_datatype.h"+#include "igraph_arpack.h"+#include "igraph_iterators.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Layouts                                            */+/* -------------------------------------------------- */++DECLDIR int igraph_layout_random(const igraph_t *graph, igraph_matrix_t *res);+DECLDIR int igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res,+                                 igraph_vs_t order);+DECLDIR int igraph_layout_star(const igraph_t *graph, igraph_matrix_t *res,+                               igraph_integer_t center, const igraph_vector_t *order);+DECLDIR int igraph_layout_grid(const igraph_t *graph, igraph_matrix_t *res, long int width);+DECLDIR int igraph_layout_fruchterman_reingold(const igraph_t *graph,+        igraph_matrix_t *res,+        igraph_bool_t use_seed,+        igraph_integer_t niter,+        igraph_real_t start_temp,+        igraph_layout_grid_t grid,+        const igraph_vector_t *weight,+        const igraph_vector_t *minx,+        const igraph_vector_t *maxx,+        const igraph_vector_t *miny,+        const igraph_vector_t *maxy);++DECLDIR int igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res,+                                       igraph_bool_t use_seed, igraph_integer_t maxiter,+                                       igraph_real_t epsilon, igraph_real_t kkconst,+                                       const igraph_vector_t *weights,+                                       const igraph_vector_t *minx, const igraph_vector_t *maxx,+                                       const igraph_vector_t *miny, const igraph_vector_t *maxy);++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR int igraph_layout_random_3d(const igraph_t *graph, igraph_matrix_t *res);+DECLDIR int igraph_layout_sphere(const igraph_t *graph, igraph_matrix_t *res);+DECLDIR int igraph_layout_grid_3d(const igraph_t *graph, igraph_matrix_t *res,+                                  long int width, long int height);+DECLDIR int igraph_layout_fruchterman_reingold_3d(const igraph_t *graph,+        igraph_matrix_t *res,+        igraph_bool_t use_seed,+        igraph_integer_t niter,+        igraph_real_t start_temp,+        const igraph_vector_t *weight,+        const igraph_vector_t *minx,+        const igraph_vector_t *maxx,+        const igraph_vector_t *miny,+        const igraph_vector_t *maxy,+        const igraph_vector_t *minz,+        const igraph_vector_t *maxz);++DECLDIR int igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res,+        igraph_bool_t use_seed, igraph_integer_t maxiter,+        igraph_real_t epsilon, igraph_real_t kkconst,+        const igraph_vector_t *weights,+        const igraph_vector_t *minx, const igraph_vector_t *maxx,+        const igraph_vector_t *miny, const igraph_vector_t *maxy,+        const igraph_vector_t *minz, const igraph_vector_t *maxz);++DECLDIR 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);++DECLDIR 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);++DECLDIR 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;++DECLDIR int igraph_layout_drl_options_init(igraph_layout_drl_options_t *options,+        igraph_layout_drl_default_t templ);+DECLDIR 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);++DECLDIR 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);++DECLDIR int igraph_layout_merge_dla(igraph_vector_ptr_t *graphs,+                                    igraph_vector_ptr_t *coords,+                                    igraph_matrix_t *res);++DECLDIR int igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res,+                              igraph_bool_t use_seed, igraph_integer_t maxiter,+                              igraph_real_t temp_max, igraph_real_t temp_min,+                              igraph_real_t temp_init);++DECLDIR int igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix_t *res,+        igraph_bool_t use_seed, igraph_integer_t maxiter,+        igraph_integer_t fineiter, igraph_real_t cool_fact,+        igraph_real_t weight_node_dist, igraph_real_t weight_border,+        igraph_real_t weight_edge_lengths,+        igraph_real_t weight_edge_crossings,+        igraph_real_t weight_node_edge_dist);++__END_DECLS++#endif
+ igraph/include/igraph_lsap.h view
@@ -0,0 +1,16 @@++#ifndef IGRAPH_LSAP+#define IGRAPH_LSAP++#include "igraph_types.h"+#include "igraph_vector.h"+#include "igraph_matrix.h"++__BEGIN_DECLS++int igraph_solve_lsap(igraph_matrix_t *c, igraph_integer_t n,+                      igraph_vector_int_t *p);++__END_DECLS++#endif
+ igraph/include/igraph_marked_queue.h view
@@ -0,0 +1,70 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/igraph_matching.h view
@@ -0,0 +1,56 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2012  Tamas Nepusz <ntamas@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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_datatype.h"+#include "igraph_types.h"+#include "igraph_vector.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Matchings in graphs                                */+/* -------------------------------------------------- */++DECLDIR int igraph_is_matching(const igraph_t* graph,+                               const igraph_vector_bool_t* types, const igraph_vector_long_t* matching,+                               igraph_bool_t* result);+DECLDIR 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);++DECLDIR 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);++DECLDIR 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
+ igraph/include/igraph_math.h view
@@ -0,0 +1,100 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2008-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++/**+ * \def IGRAPH_SHORTEST_PATH_EPSILON+ *+ * Relative error threshold used in weighted shortest path calculations+ * to decide whether two shortest paths are of equal length.+ */+#define IGRAPH_SHORTEST_PATH_EPSILON 1e-10++/*+ * 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_PI_2+    #define M_PI_2 1.57079632679489661923+#endif+#ifndef M_LN2+    #define M_LN2 0.69314718055994530942+#endif+#ifndef M_SQRT2+    #define M_SQRT2 1.4142135623730950488016887+#endif+#ifndef M_LN_SQRT_2PI+    #define M_LN_SQRT_2PI   0.918938533204672741780329736406 /* log(sqrt(2*pi))+    == log(2*pi)/2 */+#endif++int igraph_almost_equals(double a, double b, double eps);+int igraph_cmp_epsilon(double a, double b, double eps);++__END_DECLS++#endif+
+ igraph/include/igraph_matrix.h view
@@ -0,0 +1,100 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_vector.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Matrix, very similar to vector                     */+/* -------------------------------------------------- */++#define BASE_IGRAPH_REAL+#include "igraph_pmt.h"+#include "igraph_matrix_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_IGRAPH_REAL++#define BASE_INT+#include "igraph_pmt.h"+#include "igraph_matrix_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_INT++#define BASE_LONG+#include "igraph_pmt.h"+#include "igraph_matrix_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_LONG++#define BASE_CHAR+#include "igraph_pmt.h"+#include "igraph_matrix_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_CHAR++#define BASE_BOOL+#include "igraph_pmt.h"+#include "igraph_matrix_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_BOOL++#define BASE_COMPLEX+#include "igraph_pmt.h"+#include "igraph_matrix_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_COMPLEX++#define IGRAPH_MATRIX_NULL { IGRAPH_VECTOR_NULL, 0, 0 }+#define IGRAPH_MATRIX_INIT_FINALLY(m, nr, nc) \+    do { IGRAPH_CHECK(igraph_matrix_init(m, nr, nc)); \+        IGRAPH_FINALLY(igraph_matrix_destroy, m); } while (0)++/**+ * \ingroup matrix+ * \define MATRIX+ * \brief Accessing an element of a matrix.+ *+ * Note that there are no range checks right now.+ * This functionality might be redefined as a proper function later.+ * \param m The matrix object.+ * \param i The index of the row, starting with zero.+ * \param j The index of the column, starting with zero.+ *+ * Time complexity: O(1).+ */+#define MATRIX(m,i,j) ((m).data.stor_begin[(m).nrow*(j)+(i)])++igraph_bool_t igraph_matrix_all_e_tol(const igraph_matrix_t *lhs,+                                      const igraph_matrix_t *rhs,+                                      igraph_real_t tol);++int igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol);++__END_DECLS++#endif
+ igraph/include/igraph_matrix_pmt.h view
@@ -0,0 +1,243 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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    */+/*---------------*/++DECLDIR int FUNCTION(igraph_matrix, init)(TYPE(igraph_matrix) *m,+        long int nrow, long int ncol);+DECLDIR int FUNCTION(igraph_matrix, copy)(TYPE(igraph_matrix) *to,+        const TYPE(igraph_matrix) *from);+DECLDIR void FUNCTION(igraph_matrix, destroy)(TYPE(igraph_matrix) *m);+DECLDIR long int FUNCTION(igraph_matrix, capacity)(const TYPE(igraph_matrix) *m);++/*--------------------*/+/* Accessing elements */+/*--------------------*/++/* MATRIX */+DECLDIR BASE FUNCTION(igraph_matrix, e)(const TYPE(igraph_matrix) *m,+                                        long int row, long int col);+BASE* FUNCTION(igraph_matrix, e_ptr)(const TYPE(igraph_matrix) *m,+                                     long int row, long int col);+DECLDIR void FUNCTION(igraph_matrix, set)(TYPE(igraph_matrix)* m, long int row, long int col,+        BASE value);++/*------------------------------*/+/* Initializing matrix elements */+/*------------------------------*/++DECLDIR void FUNCTION(igraph_matrix, null)(TYPE(igraph_matrix) *m);+DECLDIR void FUNCTION(igraph_matrix, fill)(TYPE(igraph_matrix) *m, BASE e);++/*-----------------------*/+/* Matrix views          */+/*-----------------------*/++const TYPE(igraph_matrix) *FUNCTION(igraph_matrix, view)(const TYPE(igraph_matrix) *m,+        const BASE *data,+        long int nrow,+        long int ncol);++/*------------------*/+/* Copying matrices */+/*------------------*/++DECLDIR void FUNCTION(igraph_matrix, copy_to)(const TYPE(igraph_matrix) *m, BASE *to);+DECLDIR int FUNCTION(igraph_matrix, update)(TYPE(igraph_matrix) *to,+        const TYPE(igraph_matrix) *from);+DECLDIR int FUNCTION(igraph_matrix, rbind)(TYPE(igraph_matrix) *to,+        const TYPE(igraph_matrix) *from);+DECLDIR int FUNCTION(igraph_matrix, cbind)(TYPE(igraph_matrix) *to,+        const TYPE(igraph_matrix) *from);+DECLDIR int FUNCTION(igraph_matrix, swap)(TYPE(igraph_matrix) *m1, TYPE(igraph_matrix) *m2);++/*--------------------------*/+/* Copying rows and columns */+/*--------------------------*/++DECLDIR int FUNCTION(igraph_matrix, get_row)(const TYPE(igraph_matrix) *m,+        TYPE(igraph_vector) *res, long int index);+DECLDIR int FUNCTION(igraph_matrix, get_col)(const TYPE(igraph_matrix) *m,+        TYPE(igraph_vector) *res, long int index);+DECLDIR int FUNCTION(igraph_matrix, set_row)(TYPE(igraph_matrix) *m,+        const TYPE(igraph_vector) *v, long int index);+DECLDIR int FUNCTION(igraph_matrix, set_col)(TYPE(igraph_matrix) *m,+        const TYPE(igraph_vector) *v, long int index);+DECLDIR int FUNCTION(igraph_matrix, select_rows)(const TYPE(igraph_matrix) *m,+        TYPE(igraph_matrix) *res,+        const igraph_vector_t *rows);+DECLDIR int FUNCTION(igraph_matrix, select_cols)(const TYPE(igraph_matrix) *m,+        TYPE(igraph_matrix) *res,+        const igraph_vector_t *cols);+DECLDIR 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 */+/*-----------------------------*/++DECLDIR int FUNCTION(igraph_matrix, swap_rows)(TYPE(igraph_matrix) *m,+        long int i, long int j);+DECLDIR int FUNCTION(igraph_matrix, swap_cols)(TYPE(igraph_matrix) *m,+        long int i, long int j);+DECLDIR int FUNCTION(igraph_matrix, swap_rowcol)(TYPE(igraph_matrix) *m,+        long int i, long int j);+DECLDIR int FUNCTION(igraph_matrix, transpose)(TYPE(igraph_matrix) *m);++/*-----------------------------*/+/* Matrix operations           */+/*-----------------------------*/++DECLDIR int FUNCTION(igraph_matrix, add)(TYPE(igraph_matrix) *m1,+        const TYPE(igraph_matrix) *m2);+DECLDIR int FUNCTION(igraph_matrix, sub)(TYPE(igraph_matrix) *m1,+        const TYPE(igraph_matrix) *m2);+DECLDIR int FUNCTION(igraph_matrix, mul_elements)(TYPE(igraph_matrix) *m1,+        const TYPE(igraph_matrix) *m2);+DECLDIR int FUNCTION(igraph_matrix, div_elements)(TYPE(igraph_matrix) *m1,+        const TYPE(igraph_matrix) *m2);+DECLDIR void FUNCTION(igraph_matrix, scale)(TYPE(igraph_matrix) *m, BASE by);+DECLDIR void FUNCTION(igraph_matrix, add_constant)(TYPE(igraph_matrix) *m, BASE plus);++/*-----------------------------*/+/* Finding minimum and maximum */+/*-----------------------------*/++DECLDIR igraph_real_t FUNCTION(igraph_matrix, min)(const TYPE(igraph_matrix) *m);+DECLDIR igraph_real_t FUNCTION(igraph_matrix, max)(const TYPE(igraph_matrix) *m);+DECLDIR int FUNCTION(igraph_matrix, which_min)(const TYPE(igraph_matrix) *m,+        long int *i, long int *j);+DECLDIR int FUNCTION(igraph_matrix, which_max)(const TYPE(igraph_matrix) *m,+        long int *i, long int *j);+DECLDIR int FUNCTION(igraph_matrix, minmax)(const TYPE(igraph_matrix) *m,+        BASE *min, BASE *max);+DECLDIR int FUNCTION(igraph_matrix, which_minmax)(const TYPE(igraph_matrix) *m,+        long int *imin, long int *jmin,+        long int *imax, long int *jmax);++/*------------------------------*/+/* Comparison                   */+/*------------------------------*/++DECLDIR igraph_bool_t FUNCTION(igraph_matrix, all_e)(const TYPE(igraph_matrix) *lhs,+        const TYPE(igraph_matrix) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_matrix, all_l)(const TYPE(igraph_matrix) *lhs,+        const TYPE(igraph_matrix) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_matrix, all_g)(const TYPE(igraph_matrix) *lhs,+        const TYPE(igraph_matrix) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_matrix, all_le)(const TYPE(igraph_matrix) *lhs,+        const TYPE(igraph_matrix) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_matrix, all_ge)(const TYPE(igraph_matrix) *lhs,+        const TYPE(igraph_matrix) *rhs);++/*-------------------*/+/* Matrix properties */+/*-------------------*/++DECLDIR igraph_bool_t FUNCTION(igraph_matrix, isnull)(const TYPE(igraph_matrix) *m);+DECLDIR igraph_bool_t FUNCTION(igraph_matrix, empty)(const TYPE(igraph_matrix) *m);+DECLDIR long int FUNCTION(igraph_matrix, size)(const TYPE(igraph_matrix) *m);+DECLDIR long int FUNCTION(igraph_matrix, nrow)(const TYPE(igraph_matrix) *m);+DECLDIR long int FUNCTION(igraph_matrix, ncol)(const TYPE(igraph_matrix) *m);+DECLDIR igraph_bool_t FUNCTION(igraph_matrix, is_symmetric)(const TYPE(igraph_matrix) *m);+DECLDIR BASE FUNCTION(igraph_matrix, sum)(const TYPE(igraph_matrix) *m);+DECLDIR BASE FUNCTION(igraph_matrix, prod)(const TYPE(igraph_matrix) *m);+DECLDIR int FUNCTION(igraph_matrix, rowsum)(const TYPE(igraph_matrix) *m,+        TYPE(igraph_vector) *res);+DECLDIR int FUNCTION(igraph_matrix, colsum)(const TYPE(igraph_matrix) *m,+        TYPE(igraph_vector) *res);+DECLDIR igraph_bool_t FUNCTION(igraph_matrix, is_equal)(const TYPE(igraph_matrix) *m1,+        const TYPE(igraph_matrix) *m2);+DECLDIR igraph_real_t FUNCTION(igraph_matrix, maxdifference)(const TYPE(igraph_matrix) *m1,+        const TYPE(igraph_matrix) *m2);++/*------------------------*/+/* Searching for elements */+/*------------------------*/++DECLDIR igraph_bool_t FUNCTION(igraph_matrix, contains)(const TYPE(igraph_matrix) *m,+        BASE e);+DECLDIR 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    */+/*------------------------*/++DECLDIR int FUNCTION(igraph_matrix, resize)(TYPE(igraph_matrix) *m,+        long int nrow, long int ncol);+DECLDIR int FUNCTION(igraph_matrix, resize_min)(TYPE(igraph_matrix) *m);+DECLDIR int FUNCTION(igraph_matrix, add_cols)(TYPE(igraph_matrix) *m, long int n);+DECLDIR int FUNCTION(igraph_matrix, add_rows)(TYPE(igraph_matrix) *m, long int n);+DECLDIR int FUNCTION(igraph_matrix, remove_col)(TYPE(igraph_matrix) *m, long int col);+DECLDIR 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);+
+ igraph/include/igraph_memory.h view
@@ -0,0 +1,47 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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>+#include "igraph_decls.h"++__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 */++DECLDIR int igraph_free(void *p);+DECLDIR void *igraph_malloc(size_t n);++__END_DECLS++#endif
+ igraph/include/igraph_microscopic_update.h view
@@ -0,0 +1,60 @@+/* -*- mode: C -*-  */+/*+  Microscopic update rules for dealing with agent-level strategy revision.+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2@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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_datatype.h"+#include "igraph_iterators.h"+#include "igraph_types.h"+#include "igraph_vector.h"++__BEGIN_DECLS++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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
+ igraph/include/igraph_mixing.h view
@@ -0,0 +1,51 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_types.h"+#include "igraph_datatype.h"+#include "igraph_vector.h"++__BEGIN_DECLS++DECLDIR int igraph_assortativity_nominal(const igraph_t *graph,+        const igraph_vector_t *types,+        igraph_real_t *res,+        igraph_bool_t directed);++DECLDIR 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);++DECLDIR int igraph_assortativity_degree(const igraph_t *graph,+                                        igraph_real_t *res,+                                        igraph_bool_t directed);++__END_DECLS++#endif
+ igraph/include/igraph_motifs.h view
@@ -0,0 +1,97 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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);++DECLDIR int igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *hist,+                                  int size, const igraph_vector_t *cut_prob);++DECLDIR int igraph_motifs_randesu_callback(const igraph_t *graph, int size,+        const igraph_vector_t *cut_prob,+        igraph_motifs_handler_t *callback,+        void* extra);++DECLDIR 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);+DECLDIR int igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t *no,+                                     int size, const igraph_vector_t *cut_prob);++DECLDIR int igraph_dyad_census(const igraph_t *graph, igraph_integer_t *mut,+                               igraph_integer_t *asym, igraph_integer_t *null);+DECLDIR int igraph_triad_census(const igraph_t *igraph, igraph_vector_t *res);+DECLDIR int igraph_triad_census_24(const igraph_t *graph, igraph_real_t *res2,+                                   igraph_real_t *res4);++DECLDIR int igraph_adjacent_triangles(const igraph_t *graph,+                                      igraph_vector_t *res,+                                      const igraph_vs_t vids);++DECLDIR int igraph_list_triangles(const igraph_t *graph,+                                  igraph_vector_int_t *res);++__END_DECLS++#endif
+ igraph/include/igraph_neighborhood.h view
@@ -0,0 +1,47 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_datatype.h"+#include "igraph_iterators.h"+#include "igraph_vector_ptr.h"++__BEGIN_DECLS++DECLDIR int igraph_neighborhood_size(const igraph_t *graph, igraph_vector_t *res,+                                     igraph_vs_t vids, igraph_integer_t order,+                                     igraph_neimode_t mode, igraph_integer_t mindist);+DECLDIR int igraph_neighborhood(const igraph_t *graph, igraph_vector_ptr_t *res,+                                igraph_vs_t vids, igraph_integer_t order,+                                igraph_neimode_t mode, igraph_integer_t mindist);+DECLDIR int igraph_neighborhood_graphs(const igraph_t *graph, igraph_vector_ptr_t *res,+                                       igraph_vs_t vids, igraph_integer_t order,+                                       igraph_neimode_t mode,+                                       igraph_integer_t mindist);++__END_DECLS++#endif
+ igraph/include/igraph_nongraph.h view
@@ -0,0 +1,93 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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;++DECLDIR int igraph_running_mean(const igraph_vector_t *data, igraph_vector_t *res,+                                igraph_integer_t binwidth);+DECLDIR int igraph_fisher_yates_shuffle(igraph_vector_t *seq);+DECLDIR int igraph_random_sample(igraph_vector_t *res, igraph_real_t l, igraph_real_t h,+                                 igraph_integer_t length);+DECLDIR int igraph_convex_hull(const igraph_matrix_t *data, igraph_vector_t *resverts,+                               igraph_matrix_t *rescoords);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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
+ igraph/include/igraph_operators.h view
@@ -0,0 +1,63 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_datatype.h"+#include "igraph_vector_ptr.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Graph operators                                    */+/* -------------------------------------------------- */++DECLDIR int igraph_disjoint_union(igraph_t *res,+                                  const igraph_t *left, const igraph_t *right);+DECLDIR int igraph_disjoint_union_many(igraph_t *res,+                                       const igraph_vector_ptr_t *graphs);+DECLDIR int igraph_union(igraph_t *res, const igraph_t *left, const igraph_t *right,+                         igraph_vector_t *edge_map1, igraph_vector_t *edge_map2);+DECLDIR int igraph_union_many(igraph_t *res, const igraph_vector_ptr_t *graphs,+                              igraph_vector_ptr_t *edgemaps);+DECLDIR int igraph_intersection(igraph_t *res,+                                const igraph_t *left, const igraph_t *right,+                                igraph_vector_t *edge_map1,+                                igraph_vector_t *edge_map2);+DECLDIR int igraph_intersection_many(igraph_t *res,+                                     const igraph_vector_ptr_t *graphs,+                                     igraph_vector_ptr_t *edgemaps);+DECLDIR int igraph_difference(igraph_t *res,+                              const igraph_t *orig, const igraph_t *sub);+DECLDIR int igraph_complementer(igraph_t *res, const igraph_t *graph,+                                igraph_bool_t loops);+DECLDIR 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
+ igraph/include/igraph_paths.h view
@@ -0,0 +1,146 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_vector.h"+#include "igraph_vector_ptr.h"+#include "igraph_matrix.h"+#include "igraph_iterators.h"++__BEGIN_DECLS++DECLDIR 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);+DECLDIR 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);++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR int igraph_average_path_length(const igraph_t *graph, igraph_real_t *res,+                                       igraph_bool_t directed, igraph_bool_t unconn);+DECLDIR int igraph_path_length_hist(const igraph_t *graph, igraph_vector_t *res,+                                    igraph_real_t *unconnected, igraph_bool_t directed);++DECLDIR int igraph_eccentricity(const igraph_t *graph,+                                igraph_vector_t *res,+                                igraph_vs_t vids,+                                igraph_neimode_t mode);++DECLDIR int igraph_radius(const igraph_t *graph, igraph_real_t *radius,+                          igraph_neimode_t mode);++DECLDIR int igraph_get_all_simple_paths(const igraph_t *graph,+                                        igraph_vector_int_t *res,+                                        igraph_integer_t from,+                                        const igraph_vs_t to,+                                        igraph_integer_t cutoff,+                                        igraph_neimode_t mode);++DECLDIR int igraph_random_walk(const igraph_t *graph, igraph_vector_t *walk,+                               igraph_integer_t start, igraph_neimode_t mode,+                               igraph_integer_t steps,+                               igraph_random_walk_stuck_t stuck);++DECLDIR int igraph_random_edge_walk(const igraph_t *graph,+                                    const igraph_vector_t *weights,+                                    igraph_vector_t *edgewalk,+                                    igraph_integer_t start, igraph_neimode_t mode,+                                    igraph_integer_t steps,+                                    igraph_random_walk_stuck_t stuck);++__END_DECLS++#endif
+ igraph/include/igraph_pmt.h view
@@ -0,0 +1,150 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#define CONCAT2x(a,b) a ## _ ## b+#define CONCAT2(a,b) CONCAT2x(a,b)+#define CONCAT3x(a,b,c) a ## _ ## b ## _ ## c+#define CONCAT3(a,b,c) CONCAT3x(a,b,c)+#define CONCAT4x(a,b,c,d) a ## _ ## b ## _ ## c ## _ ## d+#define CONCAT4(a,b,c,d) CONCAT4x(a,b,c,d)++#if defined(BASE_IGRAPH_REAL)+    #define BASE igraph_real_t+    #define SHORT+    #define OUT_FORMAT "%G"+    #define PRINTFUNC(val) igraph_real_printf(val)+    #define FPRINTFUNC(file, val) igraph_real_fprintf(file, val)+    #define ZERO 0.0+    #define ONE 1.0+    #define MULTIPLICITY 1++#elif defined(BASE_FLOAT)+    #define BASE float+    #define SHORT float+    #define OUT_FORMAT "%f"+    #define ZERO 0.0F+    #define ONE 1.0F+    #define MULTIPLICITY 1++#elif defined(BASE_LONG)+    #define BASE long+    #define SHORT long+    #define OUT_FORMAT "%ld"+    #define ZERO 0L+    #define ONE 1L+    #define MULTIPLICITY 1++#elif defined(BASE_CHAR)+    #define BASE char+    #define SHORT char+    #define OUT_FORMAT "%d"+    #define ZERO 0+    #define ONE 1+    #define MULTIPLICITY 1++#elif defined(BASE_BOOL)+    #define BASE igraph_bool_t+    #define SHORT bool+    #define OUT_FORMAT "%d"+    #define ZERO 0+    #define ONE 1+    #define MULTIPLICITY 1++#elif defined(BASE_INT)+    #define BASE int+    #define SHORT int+    #define OUT_FORMAT "%d"+    #define ZERO 0+    #define ONE 1+    #define MULTIPLICITY 1++#elif defined(BASE_LIMB)+    #define BASE limb_t+    #define SHORT limb+    #define ZERO 0+    #define ONE 1+    #define MULTIPLICITY 1+    #define UNSIGNED 1++#elif defined(BASE_PTR)+    #define BASE void*+    #define SHORT ptr+    #define ZERO 0+    #define MULTIPLICITY 1++#elif defined(BASE_COMPLEX)+    #undef complex+    #define BASE igraph_complex_t+    #define SHORT complex+    #define ZERO igraph_complex(0,0)+    #define ONE {{1.0,0.0}}+    #define MULTIPLICITY 2+    #define NOTORDERED 1+    #define NOABS 1+    #define SUM(a,b,c) ((a) = igraph_complex_add((b),(c)))+    #define DIFF(a,b,c) ((a) = igraph_complex_sub((b),(c)))+    #define PROD(a,b,c) ((a) = igraph_complex_mul((b),(c)))+    #define DIV(a,b,c) ((a) = igraph_complex_div((b),(c)))+    #define EQ(a,b) IGRAPH_COMPLEX_EQ((a),(b))+    #define SQ(a) IGRAPH_REAL(igraph_complex_mul((a),(a)))++#else+    #error unknown BASE_ directive+#endif++#if defined(BASE_IGRAPH_REAL)+    #define FUNCTION(dir,name) CONCAT2(dir,name)+    #define TYPE(dir) CONCAT2(dir,t)+#elif defined(BASE_BOOL)+    /* Special case because stdbool.h defines bool as a macro to _Bool which would+    * screw things up */+    #define FUNCTION(a,c) CONCAT3x(a,bool,c)+    #define TYPE(dir) CONCAT3x(dir,bool,t)+#else+    #define FUNCTION(a,c) CONCAT3(a,SHORT,c)+    #define TYPE(dir) CONCAT3(dir,SHORT,t)+#endif++#if defined(HEAP_TYPE_MIN)+    #define HEAPMORE <+    #define HEAPMOREEQ <=+    #define HEAPLESS >+    #define HEAPLESSEQ >=+    #undef FUNCTION+    #undef TYPE+    #if defined(BASE_IGRAPH_REAL)+        #define FUNCTION(dir,name) CONCAT3(dir,min,name)+        #define TYPE(dir) CONCAT3(dir,min,t)+    #else+        #define FUNCTION(a,c) CONCAT4(a,min,SHORT,c)+        #define TYPE(dir) CONCAT4(dir,min,SHORT,t)+    #endif+#endif++#if defined(HEAP_TYPE_MAX)+    #define HEAPMORE >+    #define HEAPMOREEQ >=+    #define HEAPLESS <+    #define HEAPLESSEQ <=+#endif+
+ igraph/include/igraph_pmt_off.h view
@@ -0,0 +1,158 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/igraph_progress.h view
@@ -0,0 +1,183 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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;++DECLDIR igraph_progress_handler_t * igraph_set_progress_handler(igraph_progress_handler_t new_handler);++DECLDIR int igraph_progress(const char *message, igraph_real_t percent, void *data);++DECLDIR 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
+ igraph/include/igraph_psumtree.h view
@@ -0,0 +1,58 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_vector.h"++__BEGIN_DECLS++/*+ * Defines a partial prefix sum tree which is handy for drawing random numbers+ * from a dynamic discrete distribution. The first part (0,...,offset - 1) of+ * the vector v contains the prefixes of the values contained in the latter part+ * (offset, offset + size - 1) of vector v.+ */++typedef struct {+    igraph_vector_t v;+    long int size;+    long int offset;+} igraph_psumtree_t;++DECLDIR int igraph_psumtree_init(igraph_psumtree_t *t, long int size);+DECLDIR void igraph_psumtree_reset(igraph_psumtree_t *t);+DECLDIR void igraph_psumtree_destroy(igraph_psumtree_t *t);+DECLDIR igraph_real_t igraph_psumtree_get(const igraph_psumtree_t *t, long int idx);+DECLDIR long int igraph_psumtree_size(const igraph_psumtree_t *t);+DECLDIR int igraph_psumtree_search(const igraph_psumtree_t *t, long int *idx,+                                   igraph_real_t elem);+DECLDIR int igraph_psumtree_update(igraph_psumtree_t *t, long int idx,+                                   igraph_real_t new_value);+DECLDIR igraph_real_t igraph_psumtree_sum(const igraph_psumtree_t *t);++__END_DECLS++#endif
+ igraph/include/igraph_qsort.h view
@@ -0,0 +1,40 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@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++#include "igraph_decls.h"++#include <stddef.h>++__BEGIN_DECLS++DECLDIR void igraph_qsort(void *base, size_t nel, size_t width,+                          int (*compar)(const void *, const void *));+DECLDIR void igraph_qsort_r(void *base, size_t nel, size_t width, void *thunk,+                            int (*compar)(void *, const void *, const void *));++__END_DECLS++#endif
+ igraph/include/igraph_random.h view
@@ -0,0 +1,133 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"++__BEGIN_DECLS++#include <stdlib.h>+#include <time.h>++#include "igraph_types.h"+#include "igraph_vector.h"++/* The new RNG interface is (somewhat) modelled based on the GSL */++typedef struct igraph_rng_type_t {+    const char *name;+    unsigned long int min;+    unsigned long int max;+    int (*init)(void **state);+    void (*destroy)(void *state);+    int (*seed)(void *state, unsigned long int seed);+    unsigned long int (*get)(void *state);+    igraph_real_t (*get_real)(void *state);+    igraph_real_t (*get_norm)(void *state);+    igraph_real_t (*get_geom)(void *state, igraph_real_t p);+    igraph_real_t (*get_binom)(void *state, long int n, igraph_real_t p);+    igraph_real_t (*get_exp)(void *state, igraph_real_t rate);+    igraph_real_t (*get_gamma)(void *state, igraph_real_t shape,+                               igraph_real_t scale);+} igraph_rng_type_t;++typedef struct igraph_rng_t {+    const igraph_rng_type_t *type;+    void *state;+    int def;+} igraph_rng_t;++/* --------------------------------- */++DECLDIR int igraph_rng_init(igraph_rng_t *rng, const igraph_rng_type_t *type);+DECLDIR void igraph_rng_destroy(igraph_rng_t *rng);++DECLDIR int igraph_rng_seed(igraph_rng_t *rng, unsigned long int seed);+DECLDIR unsigned long int igraph_rng_max(igraph_rng_t *rng);+DECLDIR unsigned long int igraph_rng_min(igraph_rng_t *rng);+DECLDIR const char *igraph_rng_name(igraph_rng_t *rng);++DECLDIR long int igraph_rng_get_integer(igraph_rng_t *rng,+                                        long int l, long int h);+DECLDIR igraph_real_t igraph_rng_get_normal(igraph_rng_t *rng,+        igraph_real_t m, igraph_real_t s);+DECLDIR igraph_real_t igraph_rng_get_unif(igraph_rng_t *rng,+        igraph_real_t l, igraph_real_t h);+DECLDIR igraph_real_t igraph_rng_get_unif01(igraph_rng_t *rng);+DECLDIR igraph_real_t igraph_rng_get_geom(igraph_rng_t *rng, igraph_real_t p);+DECLDIR igraph_real_t igraph_rng_get_binom(igraph_rng_t *rng, long int n,+        igraph_real_t p);+DECLDIR igraph_real_t igraph_rng_get_exp(igraph_rng_t *rng, igraph_real_t rate);+DECLDIR unsigned long int igraph_rng_get_int31(igraph_rng_t *rng);+DECLDIR igraph_real_t igraph_rng_get_gamma(igraph_rng_t *rng, igraph_real_t shape,+        igraph_real_t scale);+DECLDIR int igraph_rng_get_dirichlet(igraph_rng_t *rng,+                                     const igraph_vector_t *alpha,+                                     igraph_vector_t *result);++/* --------------------------------- */++extern const igraph_rng_type_t igraph_rngtype_glibc2;+extern const igraph_rng_type_t igraph_rngtype_rand;+extern const igraph_rng_type_t igraph_rngtype_mt19937;++DECLDIR igraph_rng_t *igraph_rng_default(void);+DECLDIR void igraph_rng_set_default(igraph_rng_t *rng);++/* --------------------------------- */++#ifdef USING_R++void GetRNGstate(void);+void PutRNGstate(void);+#define RNG_BEGIN()    GetRNGstate()+#define RNG_END()      PutRNGstate()++double Rf_dnorm4(double x, double mu, double sigma, int give_log);+#define igraph_dnorm Rf_dnorm4++#else++#define RNG_BEGIN()      if (igraph_rng_default()->def==1) {    \+        igraph_rng_seed(igraph_rng_default(), time(0));       \+        igraph_rng_default()->def=2;                  \+    }+#define RNG_END()       /* do nothing */++DECLDIR double igraph_dnorm(double x, double mu, double sigma, int give_log);++#endif++#define RNG_INTEGER(l,h) (igraph_rng_get_integer(igraph_rng_default(),(l),(h)))+#define RNG_NORMAL(m,s)  (igraph_rng_get_normal(igraph_rng_default(),(m),(s)))+#define RNG_UNIF(l,h)    (igraph_rng_get_unif(igraph_rng_default(),(l),(h)))+#define RNG_UNIF01()     (igraph_rng_get_unif01(igraph_rng_default()))+#define RNG_GEOM(p)      (igraph_rng_get_geom(igraph_rng_default(),(p)))+#define RNG_BINOM(n,p)   (igraph_rng_get_binom(igraph_rng_default(),(n),(p)))+#define RNG_INT31()      (igraph_rng_get_int31(igraph_rng_default()))++__END_DECLS++#endif
+ igraph/include/igraph_scan.h view
@@ -0,0 +1,69 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#ifndef IGRAPH_SCAN_H+#define IGRAPH_SCAN_H++#include "igraph_decls.h"+#include "igraph_datatype.h"+#include "igraph_arpack.h"+#include "igraph_constants.h"+#include "igraph_vector_ptr.h"++__BEGIN_DECLS++DECLDIR int igraph_local_scan_0(const igraph_t *graph, igraph_vector_t *res,+                                const igraph_vector_t *weights, igraph_neimode_t mode);++DECLDIR int igraph_local_scan_0_them(const igraph_t *us, const igraph_t *them,+                                     igraph_vector_t *res,+                                     const igraph_vector_t *weigths_them,+                                     igraph_neimode_t mode);++DECLDIR int igraph_local_scan_1_ecount(const igraph_t *graph, igraph_vector_t *res,+                                       const igraph_vector_t *weights,+                                       igraph_neimode_t mode);++DECLDIR int igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_t *them,+        igraph_vector_t *res,+        const igraph_vector_t *weights,+        igraph_neimode_t mode);++DECLDIR int igraph_local_scan_k_ecount(const igraph_t *graph, int k,+                                       igraph_vector_t *res,+                                       const igraph_vector_t *weights,+                                       igraph_neimode_t mode);++DECLDIR int igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_t *them,+        int k, igraph_vector_t *res,+        const igraph_vector_t *weights_them,+        igraph_neimode_t mode);++DECLDIR int igraph_local_scan_neighborhood_ecount(const igraph_t *graph,+        igraph_vector_t *res,+        const igraph_vector_t *weights,+        const igraph_vector_ptr_t *neighborhoods);++__END_DECLS++#endif
+ igraph/include/igraph_scg.h view
@@ -0,0 +1,142 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@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"++__BEGIN_DECLS++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);++__END_DECLS++#endif
+ igraph/include/igraph_separators.h view
@@ -0,0 +1,53 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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++DECLDIR int igraph_is_separator(const igraph_t *graph,+                                const igraph_vs_t candidate,+                                igraph_bool_t *res);++DECLDIR int igraph_all_minimal_st_separators(const igraph_t *graph,+        igraph_vector_ptr_t *separators);++DECLDIR int igraph_is_minimal_separator(const igraph_t *graph,+                                        const igraph_vs_t candidate,+                                        igraph_bool_t *res);++DECLDIR int igraph_minimum_size_separators(const igraph_t *graph,+        igraph_vector_ptr_t *separators);++__END_DECLS++#endif
+ igraph/include/igraph_sparsemat.h view
@@ -0,0 +1,287 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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>++__BEGIN_DECLS++struct cs_di_sparse;+struct cs_di_symbolic;+struct cs_di_numeric;++typedef struct {+    struct cs_di_sparse *cs;+} igraph_sparsemat_t;++typedef struct {+    struct cs_di_symbolic *symbolic;+} igraph_sparsemat_symbolic_t;++typedef struct {+    struct cs_di_numeric *numeric;+} igraph_sparsemat_numeric_t;++typedef enum { IGRAPH_SPARSEMAT_TRIPLET,+               IGRAPH_SPARSEMAT_CC+             } igraph_sparsemat_type_t;++typedef struct {+    igraph_sparsemat_t *mat;+    int pos;+    int col;+} igraph_sparsemat_iterator_t;++int igraph_sparsemat_init(igraph_sparsemat_t *A, int rows, int cols, int nzmax);+int igraph_sparsemat_copy(igraph_sparsemat_t *to,+                          const igraph_sparsemat_t *from);+void igraph_sparsemat_destroy(igraph_sparsemat_t *A);+int igraph_sparsemat_realloc(igraph_sparsemat_t *A, int nzmax);++long int igraph_sparsemat_nrow(const igraph_sparsemat_t *A);+long int igraph_sparsemat_ncol(const igraph_sparsemat_t *B);+igraph_sparsemat_type_t igraph_sparsemat_type(const igraph_sparsemat_t *A);+igraph_bool_t igraph_sparsemat_is_triplet(const igraph_sparsemat_t *A);+igraph_bool_t igraph_sparsemat_is_cc(const igraph_sparsemat_t *A);++int igraph_sparsemat_permute(const igraph_sparsemat_t *A,+                             const igraph_vector_int_t *p,+                             const igraph_vector_int_t *q,+                             igraph_sparsemat_t *res);++int igraph_sparsemat_index(const igraph_sparsemat_t *A,+                           const igraph_vector_int_t *p,+                           const igraph_vector_int_t *q,+                           igraph_sparsemat_t *res,+                           igraph_real_t *constres);++int igraph_sparsemat_entry(igraph_sparsemat_t *A, int row, int col,+                           igraph_real_t elem);+int igraph_sparsemat_compress(const igraph_sparsemat_t *A,+                              igraph_sparsemat_t *res);+int igraph_sparsemat_transpose(const igraph_sparsemat_t *A,+                               igraph_sparsemat_t *res, int values);+igraph_bool_t igraph_sparsemat_is_symmetric(const igraph_sparsemat_t *A);+int igraph_sparsemat_dupl(igraph_sparsemat_t *A);+int igraph_sparsemat_fkeep(igraph_sparsemat_t *A,+                           int (*fkeep)(int, int, igraph_real_t, void*),+                           void *other);+int igraph_sparsemat_dropzeros(igraph_sparsemat_t *A);+int igraph_sparsemat_droptol(igraph_sparsemat_t *A, igraph_real_t tol);+int igraph_sparsemat_multiply(const igraph_sparsemat_t *A,+                              const igraph_sparsemat_t *B,+                              igraph_sparsemat_t *res);+int igraph_sparsemat_add(const igraph_sparsemat_t *A,+                         const igraph_sparsemat_t *B,+                         igraph_real_t alpha,+                         igraph_real_t beta,+                         igraph_sparsemat_t *res);+int igraph_sparsemat_gaxpy(const igraph_sparsemat_t *A,+                           const igraph_vector_t *x,+                           igraph_vector_t *res);++int igraph_sparsemat_lsolve(const igraph_sparsemat_t *A,+                            const igraph_vector_t *b,+                            igraph_vector_t *res);+int igraph_sparsemat_ltsolve(const igraph_sparsemat_t *A,+                             const igraph_vector_t *b,+                             igraph_vector_t *res);+int igraph_sparsemat_usolve(const igraph_sparsemat_t *A,+                            const igraph_vector_t *b,+                            igraph_vector_t *res);+int igraph_sparsemat_utsolve(const igraph_sparsemat_t *A,+                             const igraph_vector_t *b,+                             igraph_vector_t *res);++int igraph_sparsemat_cholsol(const igraph_sparsemat_t *A,+                             const igraph_vector_t *b,+                             igraph_vector_t *res,+                             int order);++int igraph_sparsemat_lusol(const igraph_sparsemat_t *A,+                           const igraph_vector_t *b,+                           igraph_vector_t *res,+                           int order,+                           igraph_real_t tol);++int igraph_sparsemat_print(const igraph_sparsemat_t *A,+                           FILE *outstream);++int igraph_sparsemat_eye(igraph_sparsemat_t *A, int n, int nzmax,+                         igraph_real_t value,+                         igraph_bool_t compress);++int igraph_sparsemat_diag(igraph_sparsemat_t *A, int nzmax,+                          const igraph_vector_t *values,+                          igraph_bool_t compress);++int igraph_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,+                     igraph_bool_t directed);++int igraph_weighted_sparsemat(igraph_t *graph, const igraph_sparsemat_t *A,+                              igraph_bool_t directed, const char *attr,+                              igraph_bool_t loops);++int igraph_get_sparsemat(const igraph_t *graph, igraph_sparsemat_t *res);++int igraph_matrix_as_sparsemat(igraph_sparsemat_t *res,+                               const igraph_matrix_t *mat,+                               igraph_real_t tol);++int igraph_sparsemat_as_matrix(igraph_matrix_t *res,+                               const igraph_sparsemat_t *spmat);++typedef enum { IGRAPH_SPARSEMAT_SOLVE_LU,+               IGRAPH_SPARSEMAT_SOLVE_QR+             } igraph_sparsemat_solve_t;++int igraph_sparsemat_arpack_rssolve(const igraph_sparsemat_t *A,+                                    igraph_arpack_options_t *options,+                                    igraph_arpack_storage_t *storage,+                                    igraph_vector_t *values,+                                    igraph_matrix_t *vectors,+                                    igraph_sparsemat_solve_t solvemethod);++int igraph_sparsemat_arpack_rnsolve(const igraph_sparsemat_t *A,+                                    igraph_arpack_options_t *options,+                                    igraph_arpack_storage_t *storage,+                                    igraph_matrix_t *values,+                                    igraph_matrix_t *vectors);++int igraph_sparsemat_lu(const igraph_sparsemat_t *A,+                        const igraph_sparsemat_symbolic_t *dis,+                        igraph_sparsemat_numeric_t *din, double tol);++int igraph_sparsemat_qr(const igraph_sparsemat_t *A,+                        const igraph_sparsemat_symbolic_t *dis,+                        igraph_sparsemat_numeric_t *din);++int igraph_sparsemat_luresol(const igraph_sparsemat_symbolic_t *dis,+                             const igraph_sparsemat_numeric_t *din,+                             const igraph_vector_t *b,+                             igraph_vector_t *res);++int igraph_sparsemat_qrresol(const igraph_sparsemat_symbolic_t *dis,+                             const igraph_sparsemat_numeric_t *din,+                             const igraph_vector_t *b,+                             igraph_vector_t *res);++int igraph_sparsemat_symbqr(long int order, const igraph_sparsemat_t *A,+                            igraph_sparsemat_symbolic_t *dis);++int igraph_sparsemat_symblu(long int order, const igraph_sparsemat_t *A,+                            igraph_sparsemat_symbolic_t *dis);+++void igraph_sparsemat_symbolic_destroy(igraph_sparsemat_symbolic_t *dis);+void igraph_sparsemat_numeric_destroy(igraph_sparsemat_numeric_t *din);++igraph_real_t igraph_sparsemat_max(igraph_sparsemat_t *A);+igraph_real_t igraph_sparsemat_min(igraph_sparsemat_t *A);+int igraph_sparsemat_minmax(igraph_sparsemat_t *A,+                            igraph_real_t *min, igraph_real_t *max);++long int igraph_sparsemat_count_nonzero(igraph_sparsemat_t *A);+long int igraph_sparsemat_count_nonzerotol(igraph_sparsemat_t *A,+        igraph_real_t tol);+int igraph_sparsemat_rowsums(const igraph_sparsemat_t *A,+                             igraph_vector_t *res);+int igraph_sparsemat_colsums(const igraph_sparsemat_t *A,+                             igraph_vector_t *res);++int igraph_sparsemat_rowmins(igraph_sparsemat_t *A,+                             igraph_vector_t *res);+int igraph_sparsemat_colmins(igraph_sparsemat_t *A,+                             igraph_vector_t *res);++int igraph_sparsemat_rowmaxs(igraph_sparsemat_t *A,+                             igraph_vector_t *res);+int igraph_sparsemat_colmaxs(igraph_sparsemat_t *A,+                             igraph_vector_t *res);++int igraph_sparsemat_which_min_rows(igraph_sparsemat_t *A,+                                    igraph_vector_t *res,+                                    igraph_vector_int_t *pos);+int igraph_sparsemat_which_min_cols(igraph_sparsemat_t *A,+                                    igraph_vector_t *res,+                                    igraph_vector_int_t *pos);++int igraph_sparsemat_scale(igraph_sparsemat_t *A, igraph_real_t by);+++int igraph_sparsemat_add_rows(igraph_sparsemat_t *A, long int n);+int igraph_sparsemat_add_cols(igraph_sparsemat_t *A, long int n);+int igraph_sparsemat_resize(igraph_sparsemat_t *A, long int nrow,+                            long int ncol, int nzmax);+int igraph_sparsemat_nonzero_storage(const igraph_sparsemat_t *A);+int igraph_sparsemat_getelements(const igraph_sparsemat_t *A,+                                 igraph_vector_int_t *i,+                                 igraph_vector_int_t *j,+                                 igraph_vector_t *x);+int igraph_sparsemat_getelements_sorted(const igraph_sparsemat_t *A,+                                        igraph_vector_int_t *i,+                                        igraph_vector_int_t *j,+                                        igraph_vector_t *x);+int igraph_sparsemat_scale_rows(igraph_sparsemat_t *A,+                                const igraph_vector_t *fact);+int igraph_sparsemat_scale_cols(igraph_sparsemat_t *A,+                                const igraph_vector_t *fact);+int igraph_sparsemat_multiply_by_dense(const igraph_sparsemat_t *A,+                                       const igraph_matrix_t *B,+                                       igraph_matrix_t *res);+int igraph_sparsemat_dense_multiply(const igraph_matrix_t *A,+                                    const igraph_sparsemat_t *B,+                                    igraph_matrix_t *res);++int igraph_i_sparsemat_view(igraph_sparsemat_t *A, int nzmax, int m, int n,+                            int *p, int *i, double *x, int nz);++int igraph_sparsemat_sort(const igraph_sparsemat_t *A,+                          igraph_sparsemat_t *sorted);++int igraph_sparsemat_nzmax(const igraph_sparsemat_t *A);++int igraph_sparsemat_neg(igraph_sparsemat_t *A);++int igraph_sparsemat_iterator_init(igraph_sparsemat_iterator_t *it,+                                   igraph_sparsemat_t *sparsemat);+int igraph_sparsemat_iterator_reset(igraph_sparsemat_iterator_t *it);+igraph_bool_t+igraph_sparsemat_iterator_end(const igraph_sparsemat_iterator_t *it);+int igraph_sparsemat_iterator_row(const igraph_sparsemat_iterator_t *it);+int igraph_sparsemat_iterator_col(const igraph_sparsemat_iterator_t *it);+int igraph_sparsemat_iterator_idx(const igraph_sparsemat_iterator_t *it);+igraph_real_t+igraph_sparsemat_iterator_get(const igraph_sparsemat_iterator_t *it);+int igraph_sparsemat_iterator_next(igraph_sparsemat_iterator_t *it);++__END_DECLS++#endif
+ igraph/include/igraph_spmatrix.h view
@@ -0,0 +1,114 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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)++DECLDIR int igraph_spmatrix_init(igraph_spmatrix_t *m, long int nrow, long int ncol);+DECLDIR void igraph_spmatrix_destroy(igraph_spmatrix_t *m);+DECLDIR int igraph_spmatrix_resize(igraph_spmatrix_t *m, long int nrow, long int ncol);+DECLDIR igraph_real_t igraph_spmatrix_e(const igraph_spmatrix_t *m, long int row, long int col);+DECLDIR int igraph_spmatrix_set(igraph_spmatrix_t *m, long int row, long int col,+                                igraph_real_t value);+DECLDIR int igraph_spmatrix_add_e(igraph_spmatrix_t *m, long int row, long int col,+                                  igraph_real_t value);+DECLDIR int igraph_spmatrix_add_col_values(igraph_spmatrix_t *m, long int to, long int from);+DECLDIR long int igraph_spmatrix_count_nonzero(const igraph_spmatrix_t *m);+DECLDIR long int igraph_spmatrix_size(const igraph_spmatrix_t *m);+DECLDIR long int igraph_spmatrix_nrow(const igraph_spmatrix_t *m);+DECLDIR long int igraph_spmatrix_ncol(const igraph_spmatrix_t *m);+DECLDIR int igraph_spmatrix_copy_to(const igraph_spmatrix_t *m, igraph_real_t *to);+DECLDIR int igraph_spmatrix_null(igraph_spmatrix_t *m);+DECLDIR int igraph_spmatrix_add_cols(igraph_spmatrix_t *m, long int n);+DECLDIR int igraph_spmatrix_add_rows(igraph_spmatrix_t *m, long int n);+DECLDIR int igraph_spmatrix_clear_col(igraph_spmatrix_t *m, long int col);+DECLDIR int igraph_spmatrix_clear_row(igraph_spmatrix_t *m, long int row);+DECLDIR int igraph_spmatrix_copy(igraph_spmatrix_t *to, const igraph_spmatrix_t *from);+DECLDIR igraph_real_t igraph_spmatrix_max_nonzero(const igraph_spmatrix_t *m,+        igraph_real_t *ridx, igraph_real_t *cidx);+DECLDIR igraph_real_t igraph_spmatrix_max(const igraph_spmatrix_t *m,+        igraph_real_t *ridx, igraph_real_t *cidx);+DECLDIR void igraph_spmatrix_scale(igraph_spmatrix_t *m, igraph_real_t by);+DECLDIR int igraph_spmatrix_colsums(const igraph_spmatrix_t *m, igraph_vector_t *res);+DECLDIR int igraph_spmatrix_rowsums(const igraph_spmatrix_t *m, igraph_vector_t *res);++DECLDIR int igraph_spmatrix_print(const igraph_spmatrix_t *matrix);+DECLDIR int igraph_spmatrix_fprint(const igraph_spmatrix_t *matrix, FILE* file);++DECLDIR int igraph_i_spmatrix_get_col_nonzero_indices(const igraph_spmatrix_t *m,+        igraph_vector_t *res, long int col);+DECLDIR int igraph_i_spmatrix_clear_row_fast(igraph_spmatrix_t *m, long int row);+DECLDIR 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;++DECLDIR int igraph_spmatrix_iter_create(igraph_spmatrix_iter_t *mit, const igraph_spmatrix_t *m);+DECLDIR int igraph_spmatrix_iter_reset(igraph_spmatrix_iter_t *mit);+DECLDIR int igraph_spmatrix_iter_next(igraph_spmatrix_iter_t *mit);+DECLDIR igraph_bool_t igraph_spmatrix_iter_end(igraph_spmatrix_iter_t *mit);+DECLDIR void igraph_spmatrix_iter_destroy(igraph_spmatrix_iter_t *mit);++__END_DECLS++#endif
+ igraph/include/igraph_stack.h view
@@ -0,0 +1,79 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_types.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Plain stack                                        */+/* -------------------------------------------------- */++#define BASE_IGRAPH_REAL+#include "igraph_pmt.h"+#include "igraph_stack_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_IGRAPH_REAL++#define BASE_LONG+#include "igraph_pmt.h"+#include "igraph_stack_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_LONG++#define BASE_INT+#include "igraph_pmt.h"+#include "igraph_stack_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_INT++#define BASE_CHAR+#include "igraph_pmt.h"+#include "igraph_stack_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_CHAR++#define BASE_BOOL+#include "igraph_pmt.h"+#include "igraph_stack_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_BOOL++#define BASE_PTR+#include "igraph_pmt.h"+#include "igraph_stack_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_PTR++#define IGRAPH_STACK_NULL { 0,0,0 }++void igraph_stack_ptr_free_all(igraph_stack_ptr_t* s);+void igraph_stack_ptr_destroy_all(igraph_stack_ptr_t* s);++__END_DECLS++#endif
+ igraph/include/igraph_stack_pmt.h view
@@ -0,0 +1,47 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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);++DECLDIR int FUNCTION(igraph_stack, init)(TYPE(igraph_stack)* s, long int size);+DECLDIR void FUNCTION(igraph_stack, destroy)(TYPE(igraph_stack)* s);+DECLDIR int FUNCTION(igraph_stack, reserve)(TYPE(igraph_stack)* s, long int size);+DECLDIR igraph_bool_t FUNCTION(igraph_stack, empty)(TYPE(igraph_stack)* s);+DECLDIR long int FUNCTION(igraph_stack, size)(const TYPE(igraph_stack)* s);+DECLDIR void FUNCTION(igraph_stack, clear)(TYPE(igraph_stack)* s);+DECLDIR int FUNCTION(igraph_stack, push)(TYPE(igraph_stack)* s, BASE elem);+DECLDIR BASE FUNCTION(igraph_stack, pop)(TYPE(igraph_stack)* s);+DECLDIR BASE FUNCTION(igraph_stack, top)(const TYPE(igraph_stack)* s);+DECLDIR int FUNCTION(igraph_stack, print)(const TYPE(igraph_stack)* s);+DECLDIR int FUNCTION(igraph_stack, fprint)(const TYPE(igraph_stack)* s, FILE *file);
+ igraph/include/igraph_statusbar.h view
@@ -0,0 +1,126 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"++__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;++DECLDIR igraph_status_handler_t * igraph_set_status_handler(igraph_status_handler_t new_handler);++DECLDIR 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)++DECLDIR 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
+ igraph/include/igraph_structural.h view
@@ -0,0 +1,151 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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                              */+/* -------------------------------------------------- */++DECLDIR int igraph_are_connected(const igraph_t *graph, igraph_integer_t v1, igraph_integer_t v2, igraph_bool_t *res);++/* -------------------------------------------------- */+/* Structural properties                              */+/* -------------------------------------------------- */++DECLDIR int igraph_minimum_spanning_tree(const igraph_t *graph, igraph_vector_t *res,+        const igraph_vector_t *weights);+DECLDIR int igraph_minimum_spanning_tree_unweighted(const igraph_t *graph,+        igraph_t *mst);+DECLDIR int igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst,+        const igraph_vector_t *weights);+DECLDIR int igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_t *res,+                                        igraph_integer_t vid);++DECLDIR int igraph_subcomponent(const igraph_t *graph, igraph_vector_t *res, igraph_real_t vid,+                                igraph_neimode_t mode);+DECLDIR int igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode);+DECLDIR int igraph_subgraph(const igraph_t *graph, igraph_t *res,+                            const igraph_vs_t vids);+DECLDIR 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);+DECLDIR int igraph_induced_subgraph(const igraph_t *graph, igraph_t *res,+                                    const igraph_vs_t vids, igraph_subgraph_implementation_t impl);+DECLDIR int igraph_subgraph_edges(const igraph_t *graph, igraph_t *res,+                                  const igraph_es_t eids, igraph_bool_t delete_vertices);+DECLDIR int igraph_simplify(igraph_t *graph, igraph_bool_t multiple,+                            igraph_bool_t loops,+                            const igraph_attribute_combination_t *edge_comb);+DECLDIR int igraph_reciprocity(const igraph_t *graph, igraph_real_t *res,+                               igraph_bool_t ignore_loops,+                               igraph_reciprocity_t mode);++DECLDIR int igraph_maxdegree(const igraph_t *graph, igraph_integer_t *res,+                             igraph_vs_t vids, igraph_neimode_t mode,+                             igraph_bool_t loops);+DECLDIR int igraph_density(const igraph_t *graph, igraph_real_t *res,+                           igraph_bool_t loops);++DECLDIR int igraph_has_loop(const igraph_t *graph, igraph_bool_t *res);+DECLDIR int igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res,+                           igraph_es_t es);+DECLDIR int igraph_is_simple(const igraph_t *graph, igraph_bool_t *res);+DECLDIR int igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res);+DECLDIR int igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res,+                               igraph_es_t es);+DECLDIR int igraph_count_multiple(const igraph_t *graph, igraph_vector_t *res, igraph_es_t es);+DECLDIR int igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_integer_t *root, igraph_neimode_t mode);+DECLDIR int igraph_girth(const igraph_t *graph, igraph_integer_t *girth,+                         igraph_vector_t *circle);+DECLDIR int igraph_add_edge(igraph_t *graph, igraph_integer_t from, igraph_integer_t to);++DECLDIR 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);++DECLDIR int igraph_is_mutual(igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es);++DECLDIR int igraph_maximum_cardinality_search(const igraph_t *graph,+        igraph_vector_t *alpha,+        igraph_vector_t *alpham1);+DECLDIR 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);+DECLDIR int igraph_avg_nearest_neighbor_degree(const igraph_t *graph,+        igraph_vs_t vids,+        igraph_neimode_t mode,+        igraph_neimode_t neighbor_degree_mode,+        igraph_vector_t *knn,+        igraph_vector_t *knnk,+        const igraph_vector_t *weights);+DECLDIR int igraph_contract_vertices(igraph_t *graph,+                                     const igraph_vector_t *mapping,+                                     const igraph_attribute_combination_t+                                     *vertex_comb);++DECLDIR int igraph_feedback_arc_set(const igraph_t *graph, igraph_vector_t *result,+                                    const igraph_vector_t *weights, igraph_fas_algorithm_t algo);++DECLDIR int igraph_diversity(igraph_t *graph, const igraph_vector_t *weights,+                             igraph_vector_t *res, const igraph_vs_t vs);++/* -------------------------------------------------- */+/* Spectral Properties                                */+/* -------------------------------------------------- */++DECLDIR 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
+ igraph/include/igraph_strvector.h view
@@ -0,0 +1,97 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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)++DECLDIR int igraph_strvector_init(igraph_strvector_t *sv, long int len);+DECLDIR void igraph_strvector_destroy(igraph_strvector_t *sv);+DECLDIR long int igraph_strvector_size(const igraph_strvector_t *sv);+DECLDIR void igraph_strvector_get(const igraph_strvector_t *sv,+                                  long int idx, char **value);+DECLDIR int igraph_strvector_set(igraph_strvector_t *sv, long int idx,+                                 const char *value);+DECLDIR int igraph_strvector_set2(igraph_strvector_t *sv, long int idx,+                                  const char *value, int len);+DECLDIR void igraph_strvector_clear(igraph_strvector_t *sv);+DECLDIR void igraph_strvector_remove_section(igraph_strvector_t *v, long int from,+        long int to);+DECLDIR void igraph_strvector_remove(igraph_strvector_t *v, long int elem);+DECLDIR void igraph_strvector_move_interval(igraph_strvector_t *v, long int begin,+        long int end, long int to);+DECLDIR int igraph_strvector_copy(igraph_strvector_t *to,+                                  const igraph_strvector_t *from);+DECLDIR int igraph_strvector_append(igraph_strvector_t *to,+                                    const igraph_strvector_t *from);+DECLDIR int igraph_strvector_resize(igraph_strvector_t* v, long int newsize);+DECLDIR int igraph_strvector_add(igraph_strvector_t *v, const char *value);+DECLDIR void igraph_strvector_permdelete(igraph_strvector_t *v, const igraph_vector_t *index,+        long int nremove);+DECLDIR void igraph_strvector_remove_negidx(igraph_strvector_t *v, const igraph_vector_t *neg,+        long int nremove);+DECLDIR int igraph_strvector_print(const igraph_strvector_t *v, FILE *file,+                                   const char *sep);++DECLDIR int igraph_strvector_index(const igraph_strvector_t *v,+                                   igraph_strvector_t *newv,+                                   const igraph_vector_t *idx);+++__END_DECLS++#endif
+ igraph/include/igraph_threading.h view
@@ -0,0 +1,43 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"++__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 0++__END_DECLS++#endif+
+ igraph/include/igraph_topology.h view
@@ -0,0 +1,292 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_constants.h"+#include "igraph_datatype.h"+#include "igraph_types.h"+#include "igraph_vector_ptr.h"++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Degree sequences                                   */+/* -------------------------------------------------- */++DECLDIR int igraph_is_degree_sequence(const igraph_vector_t *out_degrees,+                                      const igraph_vector_t *in_degrees, igraph_bool_t *res);+DECLDIR 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                            */+/* -------------------------------------------------- */++DECLDIR int igraph_topological_sorting(const igraph_t *graph, igraph_vector_t *res,+                                       igraph_neimode_t mode);+DECLDIR int igraph_is_dag(const igraph_t *graph, igraph_bool_t *res);+DECLDIR int igraph_transitive_closure_dag(const igraph_t *graph,+        igraph_t *closure);++/* -------------------------------------------------- */+/* Graph isomorphisms                                 */+/* -------------------------------------------------- */++/* Common functions */+DECLDIR int igraph_permute_vertices(const igraph_t *graph, igraph_t *res,+                                    const igraph_vector_t *permutation);++DECLDIR int igraph_simplify_and_colorize(+    const igraph_t *graph, igraph_t *res,+    igraph_vector_int_t *vertex_color, igraph_vector_int_t *edge_color);++/* Generic interface */+DECLDIR int igraph_isomorphic(const igraph_t *graph1, const igraph_t *graph2,+                              igraph_bool_t *iso);+DECLDIR int igraph_subisomorphic(const igraph_t *graph1, const igraph_t *graph2,+                                 igraph_bool_t *iso);++/* LAD */+DECLDIR 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);++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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);++DECLDIR 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);+DECLDIR 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);+DECLDIR 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);+DECLDIR 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 nof_generators Number of generators of the automorphism group.+ * \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+ *    \ref igraph_free() 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 nof_generators;+    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;++DECLDIR int igraph_canonical_permutation(const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_t *labeling,+        igraph_bliss_sh_t sh, igraph_bliss_info_t *info);+DECLDIR int igraph_isomorphic_bliss(const igraph_t *graph1, const igraph_t *graph2,+                                    const igraph_vector_int_t *colors1, const igraph_vector_int_t *colors2,+                                    igraph_bool_t *iso, igraph_vector_t *map12,+                                    igraph_vector_t *map21,+                                    igraph_bliss_sh_t sh,+                                    igraph_bliss_info_t *info1, igraph_bliss_info_t *info2);++DECLDIR int igraph_automorphisms(const igraph_t *graph, const igraph_vector_int_t *colors,+                                 igraph_bliss_sh_t sh, igraph_bliss_info_t *info);++DECLDIR int igraph_automorphism_group(const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_ptr_t *generators,+                                      igraph_bliss_sh_t sh, igraph_bliss_info_t *info);++/* Functions for 3-4 graphs */+DECLDIR int igraph_isomorphic_34(const igraph_t *graph1, const igraph_t *graph2,+                                 igraph_bool_t *iso);+DECLDIR int igraph_isoclass(const igraph_t *graph, igraph_integer_t *isoclass);+DECLDIR int igraph_isoclass_subgraph(const igraph_t *graph, igraph_vector_t *vids,+                                     igraph_integer_t *isoclass);+DECLDIR int igraph_isoclass_create(igraph_t *graph, igraph_integer_t size,+                                   igraph_integer_t number, igraph_bool_t directed);+++++__END_DECLS++#endif
+ igraph/include/igraph_transitivity.h view
@@ -0,0 +1,64 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_datatype.h"+#include "igraph_constants.h"+#include "igraph_iterators.h"++__BEGIN_DECLS++DECLDIR int igraph_transitivity_undirected(const igraph_t *graph,+        igraph_real_t *res,+        igraph_transitivity_mode_t mode);+DECLDIR int igraph_transitivity_local_undirected(const igraph_t *graph,+        igraph_vector_t *res,+        const igraph_vs_t vids,+        igraph_transitivity_mode_t mode);+DECLDIR int igraph_transitivity_local_undirected1(const igraph_t *graph,+        igraph_vector_t *res,+        const igraph_vs_t vids,+        igraph_transitivity_mode_t mode);+DECLDIR int igraph_transitivity_local_undirected2(const igraph_t *graph,+        igraph_vector_t *res,+        const igraph_vs_t vids,+        igraph_transitivity_mode_t mode);+DECLDIR int igraph_transitivity_local_undirected4(const igraph_t *graph,+        igraph_vector_t *res,+        const igraph_vs_t vids,+        igraph_transitivity_mode_t mode);+DECLDIR int igraph_transitivity_avglocal_undirected(const igraph_t *graph,+        igraph_real_t *res,+        igraph_transitivity_mode_t mode);+DECLDIR 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
+ igraph/include/igraph_types.h view
@@ -0,0 +1,91 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"++__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) */+DECLDIR int igraph_real_printf(igraph_real_t val);+DECLDIR int igraph_real_fprintf(FILE *file, igraph_real_t val);+DECLDIR 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 */+DECLDIR int igraph_real_printf_precise(igraph_real_t val);+DECLDIR int igraph_real_fprintf_precise(FILE *file, igraph_real_t val);+DECLDIR 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++DECLDIR int igraph_finite(double x);+#define IGRAPH_FINITE(x) igraph_finite(x)++DECLDIR int igraph_is_nan(double x);+DECLDIR int igraph_is_inf(double x);+DECLDIR int igraph_is_posinf(double x);+DECLDIR 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
+ igraph/include/igraph_types_internal.h view
@@ -0,0 +1,395 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/igraph_vector.h view
@@ -0,0 +1,184 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#include "igraph_types.h"+#include "igraph_complex.h"++#ifdef HAVE_STDINT_H+    #include <stdint.h>+#else+    #if defined(HAVE_SYS_INT_TYPES_H) && HAVE_SYS_INT_TYPES_H+        #include <sys/int_types.h>    /* for Solaris */+    #endif+#endif++__BEGIN_DECLS++/* -------------------------------------------------- */+/* Flexible vector                                    */+/* -------------------------------------------------- */++#define BASE_IGRAPH_REAL+#include "igraph_pmt.h"+#include "igraph_vector_type.h"+#include "igraph_pmt_off.h"+#undef BASE_IGRAPH_REAL++#define BASE_FLOAT+#include "igraph_pmt.h"+#include "igraph_vector_type.h"+#include "igraph_pmt_off.h"+#undef BASE_FLOAT++#define BASE_LONG+#include "igraph_pmt.h"+#include "igraph_vector_type.h"+#include "igraph_pmt_off.h"+#undef BASE_LONG++#define BASE_CHAR+#include "igraph_pmt.h"+#include "igraph_vector_type.h"+#include "igraph_pmt_off.h"+#undef BASE_CHAR++#define BASE_BOOL+#include "igraph_pmt.h"+#include "igraph_vector_type.h"+#include "igraph_pmt_off.h"+#undef BASE_BOOL++#define BASE_INT+#include "igraph_pmt.h"+#include "igraph_vector_type.h"+#include "igraph_pmt_off.h"+#undef BASE_INT++#define BASE_COMPLEX+#include "igraph_pmt.h"+#include "igraph_vector_type.h"+#include "igraph_pmt_off.h"+#undef BASE_COMPLEX++#define BASE_IGRAPH_REAL+#include "igraph_pmt.h"+#include "igraph_vector_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_IGRAPH_REAL++#define BASE_FLOAT+#include "igraph_pmt.h"+#include "igraph_vector_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_FLOAT++#define BASE_LONG+#include "igraph_pmt.h"+#include "igraph_vector_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_LONG++#define BASE_CHAR+#include "igraph_pmt.h"+#include "igraph_vector_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_CHAR++#define BASE_BOOL+#include "igraph_pmt.h"+#include "igraph_vector_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_BOOL++#define BASE_INT+#include "igraph_pmt.h"+#include "igraph_vector_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_INT++#define BASE_COMPLEX+#include "igraph_pmt.h"+#include "igraph_vector_pmt.h"+#include "igraph_pmt_off.h"+#undef BASE_COMPLEX++/* -------------------------------------------------- */+/* Helper macros                                      */+/* -------------------------------------------------- */++#ifndef IGRAPH_VECTOR_NULL+    #define IGRAPH_VECTOR_NULL { 0,0,0 }+#endif++#ifndef IGRAPH_VECTOR_INIT_FINALLY+#define IGRAPH_VECTOR_INIT_FINALLY(v, size) \+    do { IGRAPH_CHECK(igraph_vector_init(v, size)); \+        IGRAPH_FINALLY(igraph_vector_destroy, v); } while (0)+#endif+#ifndef IGRAPH_VECTOR_BOOL_INIT_FINALLY+#define IGRAPH_VECTOR_BOOL_INIT_FINALLY(v, size) \+    do { IGRAPH_CHECK(igraph_vector_bool_init(v, size)); \+        IGRAPH_FINALLY(igraph_vector_bool_destroy, v); } while (0)+#endif+#ifndef IGRAPH_VECTOR_INT_INIT_FINALLY+#define IGRAPH_VECTOR_INT_INIT_FINALLY(v, size) \+    do { IGRAPH_CHECK(igraph_vector_int_init(v, size)); \+        IGRAPH_FINALLY(igraph_vector_int_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                     */+/* -------------------------------------------------- */++DECLDIR int igraph_vector_floor(const igraph_vector_t *from, igraph_vector_long_t *to);+DECLDIR int igraph_vector_round(const igraph_vector_t *from, igraph_vector_long_t *to);++DECLDIR igraph_bool_t igraph_vector_e_tol(const igraph_vector_t *lhs,+        const igraph_vector_t *rhs,+        igraph_real_t tol);++DECLDIR int igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol);++/* These are for internal use only */+int igraph_vector_order(const igraph_vector_t* v, const igraph_vector_t *v2,+                        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
+ igraph/include/igraph_vector_pmt.h view
@@ -0,0 +1,265 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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         */+/*--------------------*/++DECLDIR int FUNCTION(igraph_vector, init)(TYPE(igraph_vector)* v, long int size);+DECLDIR int FUNCTION(igraph_vector, init_copy)(TYPE(igraph_vector)* v,+        const BASE* data, long int length);+DECLDIR int FUNCTION(igraph_vector, init_seq)(TYPE(igraph_vector)*v, BASE from, BASE to);+DECLDIR int FUNCTION(igraph_vector, copy)(TYPE(igraph_vector) *to,+        const TYPE(igraph_vector) *from);+DECLDIR void FUNCTION(igraph_vector, destroy)(TYPE(igraph_vector)* v);++DECLDIR 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++DECLDIR BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector)* v, long int pos);+BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector)* v, long int pos);+DECLDIR void FUNCTION(igraph_vector, set)(TYPE(igraph_vector)* v, long int pos, BASE value);+DECLDIR BASE FUNCTION(igraph_vector, tail)(const TYPE(igraph_vector) *v);++/*-----------------------*/+/* Initializing elements */+/*-----------------------*/++DECLDIR void FUNCTION(igraph_vector, null)(TYPE(igraph_vector)* v);+DECLDIR void FUNCTION(igraph_vector, fill)(TYPE(igraph_vector)* v, BASE e);++/*-----------------------*/+/* Vector views          */+/*-----------------------*/++DECLDIR const TYPE(igraph_vector) *FUNCTION(igraph_vector, view)(const TYPE(igraph_vector) *v,+        const BASE *data,+        long int length);++/*-----------------------*/+/* Copying vectors       */+/*-----------------------*/++DECLDIR void FUNCTION(igraph_vector, copy_to)(const TYPE(igraph_vector) *v, BASE* to);+DECLDIR int FUNCTION(igraph_vector, update)(TYPE(igraph_vector) *to,+        const TYPE(igraph_vector) *from);+DECLDIR int FUNCTION(igraph_vector, append)(TYPE(igraph_vector) *to,+        const TYPE(igraph_vector) *from);+DECLDIR int FUNCTION(igraph_vector, swap)(TYPE(igraph_vector) *v1, TYPE(igraph_vector) *v2);++/*-----------------------*/+/* Exchanging elements   */+/*-----------------------*/++DECLDIR int FUNCTION(igraph_vector, swap_elements)(TYPE(igraph_vector) *v,+        long int i, long int j);+DECLDIR int FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v);+DECLDIR int FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v);++/*-----------------------*/+/* Vector operations     */+/*-----------------------*/++DECLDIR void FUNCTION(igraph_vector, add_constant)(TYPE(igraph_vector) *v, BASE plus);+DECLDIR void FUNCTION(igraph_vector, scale)(TYPE(igraph_vector) *v, BASE by);+DECLDIR int FUNCTION(igraph_vector, add)(TYPE(igraph_vector) *v1,+        const TYPE(igraph_vector) *v2);+DECLDIR int FUNCTION(igraph_vector, sub)(TYPE(igraph_vector) *v1,+        const TYPE(igraph_vector) *v2);+DECLDIR int FUNCTION(igraph_vector, mul)(TYPE(igraph_vector) *v1,+        const TYPE(igraph_vector) *v2);+DECLDIR int FUNCTION(igraph_vector, div)(TYPE(igraph_vector) *v1,+        const TYPE(igraph_vector) *v2);+DECLDIR int FUNCTION(igraph_vector, cumsum)(TYPE(igraph_vector) *to,+        const TYPE(igraph_vector) *from);++#ifndef NOABS+    DECLDIR int FUNCTION(igraph_vector, abs)(TYPE(igraph_vector) *v);+#endif++/*------------------------------*/+/* Comparison                   */+/*------------------------------*/++DECLDIR igraph_bool_t FUNCTION(igraph_vector, all_e)(const TYPE(igraph_vector) *lhs,+        const TYPE(igraph_vector) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, all_l)(const TYPE(igraph_vector) *lhs,+        const TYPE(igraph_vector) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, all_g)(const TYPE(igraph_vector) *lhs,+        const TYPE(igraph_vector) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, all_le)(const TYPE(igraph_vector) *lhs,+        const TYPE(igraph_vector) *rhs);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, all_ge)(const TYPE(igraph_vector) *lhs,+        const TYPE(igraph_vector) *rhs);++/*------------------------------*/+/* Finding minimum and maximum  */+/*------------------------------*/++DECLDIR BASE FUNCTION(igraph_vector, min)(const TYPE(igraph_vector)* v);+DECLDIR BASE FUNCTION(igraph_vector, max)(const TYPE(igraph_vector)* v);+DECLDIR long int FUNCTION(igraph_vector, which_min)(const TYPE(igraph_vector)* v);+DECLDIR long int FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector)* v);+DECLDIR int FUNCTION(igraph_vector, minmax)(const TYPE(igraph_vector) *v,+        BASE *min, BASE *max);+DECLDIR int FUNCTION(igraph_vector, which_minmax)(const TYPE(igraph_vector) *v,+        long int *which_min, long int *which_max);++/*-------------------*/+/* Vector properties */+/*-------------------*/++DECLDIR igraph_bool_t FUNCTION(igraph_vector, empty)     (const TYPE(igraph_vector)* v);+DECLDIR long int FUNCTION(igraph_vector, size)      (const TYPE(igraph_vector)* v);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, isnull)(const TYPE(igraph_vector) *v);+DECLDIR BASE FUNCTION(igraph_vector, sum)(const TYPE(igraph_vector) *v);+DECLDIR igraph_real_t FUNCTION(igraph_vector, sumsq)(const TYPE(igraph_vector) *v);+DECLDIR BASE FUNCTION(igraph_vector, prod)(const TYPE(igraph_vector) *v);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, isininterval)(const TYPE(igraph_vector) *v,+        BASE low, BASE high);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, any_smaller)(const TYPE(igraph_vector) *v,+        BASE limit);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, is_equal)(const TYPE(igraph_vector) *lhs,+        const TYPE(igraph_vector) *rhs);+DECLDIR igraph_real_t FUNCTION(igraph_vector, maxdifference)(const TYPE(igraph_vector) *m1,+        const TYPE(igraph_vector) *m2);++/*------------------------*/+/* Searching for elements */+/*------------------------*/++DECLDIR igraph_bool_t FUNCTION(igraph_vector, contains)(const TYPE(igraph_vector) *v, BASE e);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, search)(const TYPE(igraph_vector) *v,+        long int from, BASE what,+        long int *pos);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, binsearch)(const TYPE(igraph_vector) *v,+        BASE what, long int *pos);+DECLDIR igraph_bool_t FUNCTION(igraph_vector, binsearch2)(const TYPE(igraph_vector) *v,+        BASE what);++/*------------------------*/+/* Resizing operations    */+/*------------------------*/++DECLDIR void FUNCTION(igraph_vector, clear)(TYPE(igraph_vector)* v);+DECLDIR int FUNCTION(igraph_vector, resize)(TYPE(igraph_vector)* v, long int newsize);+DECLDIR int FUNCTION(igraph_vector, resize_min)(TYPE(igraph_vector)*v);+DECLDIR int FUNCTION(igraph_vector, reserve)(TYPE(igraph_vector)* v, long int size);+DECLDIR int FUNCTION(igraph_vector, push_back)(TYPE(igraph_vector)* v, BASE e);+DECLDIR BASE FUNCTION(igraph_vector, pop_back)(TYPE(igraph_vector)* v);+DECLDIR int FUNCTION(igraph_vector, insert)(TYPE(igraph_vector) *v, long int pos, BASE value);+DECLDIR void FUNCTION(igraph_vector, remove)(TYPE(igraph_vector) *v, long int elem);+DECLDIR void FUNCTION(igraph_vector, remove_section)(TYPE(igraph_vector) *v,+        long int from, long int to);++/*-----------*/+/* Sorting   */+/*-----------*/++DECLDIR void FUNCTION(igraph_vector, sort)(TYPE(igraph_vector) *v);+DECLDIR long int FUNCTION(igraph_vector, qsort_ind)(TYPE(igraph_vector) *v,+        igraph_vector_t *inds, igraph_bool_t descending);++/*-----------*/+/* 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++DECLDIR int igraph_vector_complex_real(const igraph_vector_complex_t *v,+                                       igraph_vector_t *real);+DECLDIR int igraph_vector_complex_imag(const igraph_vector_complex_t *v,+                                       igraph_vector_t *imag);+DECLDIR int igraph_vector_complex_realimag(const igraph_vector_complex_t *v,+        igraph_vector_t *real,+        igraph_vector_t *imag);+DECLDIR int igraph_vector_complex_create(igraph_vector_complex_t *v,+        const igraph_vector_t *real,+        const igraph_vector_t *imag);+DECLDIR 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);
+ igraph/include/igraph_vector_ptr.h view
@@ -0,0 +1,100 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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)++DECLDIR int igraph_vector_ptr_init      (igraph_vector_ptr_t* v, long int size);+DECLDIR int igraph_vector_ptr_init_copy (igraph_vector_ptr_t* v, void** data, long int length);+DECLDIR const igraph_vector_ptr_t *igraph_vector_ptr_view (const igraph_vector_ptr_t *v,+        void *const *data, long int length);+DECLDIR void igraph_vector_ptr_destroy   (igraph_vector_ptr_t* v);+DECLDIR void igraph_vector_ptr_free_all   (igraph_vector_ptr_t* v);+DECLDIR void igraph_vector_ptr_destroy_all   (igraph_vector_ptr_t* v);+DECLDIR int igraph_vector_ptr_reserve   (igraph_vector_ptr_t* v, long int size);+DECLDIR igraph_bool_t igraph_vector_ptr_empty     (const igraph_vector_ptr_t* v);+DECLDIR long int igraph_vector_ptr_size      (const igraph_vector_ptr_t* v);+DECLDIR void igraph_vector_ptr_clear     (igraph_vector_ptr_t* v);+DECLDIR void igraph_vector_ptr_null      (igraph_vector_ptr_t* v);+DECLDIR int igraph_vector_ptr_push_back (igraph_vector_ptr_t* v, void* e);+DECLDIR int igraph_vector_ptr_append    (igraph_vector_ptr_t *to,+        const igraph_vector_ptr_t *from);+DECLDIR void *igraph_vector_ptr_pop_back (igraph_vector_ptr_t *v);+DECLDIR int igraph_vector_ptr_insert(igraph_vector_ptr_t *v, long int pos, void* e);+DECLDIR void* igraph_vector_ptr_e         (const igraph_vector_ptr_t* v, long int pos);+DECLDIR void igraph_vector_ptr_set       (igraph_vector_ptr_t* v, long int pos, void* value);+DECLDIR int igraph_vector_ptr_resize(igraph_vector_ptr_t* v, long int newsize);+DECLDIR void igraph_vector_ptr_copy_to(const igraph_vector_ptr_t *v, void** to);+DECLDIR int igraph_vector_ptr_copy(igraph_vector_ptr_t *to, const igraph_vector_ptr_t *from);+DECLDIR void igraph_vector_ptr_remove(igraph_vector_ptr_t *v, long int pos);+DECLDIR void igraph_vector_ptr_sort(igraph_vector_ptr_t *v, int(*compar)(const void*, const void*));+DECLDIR int igraph_vector_ptr_index_int(igraph_vector_ptr_t *v,+                                        const igraph_vector_int_t *idx);++DECLDIR igraph_finally_func_t* igraph_vector_ptr_get_item_destructor(const igraph_vector_ptr_t *v);+DECLDIR 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
+ igraph/include/igraph_vector_type.h view
@@ -0,0 +1,34 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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);+
+ igraph/include/igraph_version.h view
@@ -0,0 +1,46 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"++__BEGIN_DECLS++#define IGRAPH_VERSION "0.8.0"+#define IGRAPH_VERSION_MAJOR 0+#define IGRAPH_VERSION_MINOR 8+#define IGRAPH_VERSION_PATCH 0+#define IGRAPH_VERSION_PRERELEASE ""++int igraph_version(const char **version_string,+                   int *major,+                   int *minor,+                   int *subminor);++__END_DECLS++#endif++
+ igraph/include/igraph_visitor.h view
@@ -0,0 +1,132 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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++#include "igraph_decls.h"+#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);++DECLDIR 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);++DECLDIR 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
+ igraph/include/infomap_FlowGraph.h view
@@ -0,0 +1,78 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/infomap_Greedy.h view
@@ -0,0 +1,85 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/infomap_Node.h view
@@ -0,0 +1,55 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/matrix.pmt view
@@ -0,0 +1,1634 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}++const TYPE(igraph_matrix) *FUNCTION(igraph_matrix, view)(const TYPE(igraph_matrix) *m,+        const BASE *data,+        long int nrow,+        long int ncol) {+    TYPE(igraph_matrix) *m2 = (TYPE(igraph_matrix)*)m;+    FUNCTION(igraph_vector, view)(&m2->data, data, nrow * ncol);+    m2->nrow = nrow;+    m2->ncol = ncol;+    return m;+}++/**+ * \ingroup matrix+ * \function igraph_matrix_destroy+ * \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.+ */++igraph_real_t 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
+ igraph/include/maximal_cliques_template.h view
@@ -0,0 +1,409 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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_CHECK(igraph_vector_ptr_push_back(res, cl));             \+        IGRAPH_CHECK(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_CHECK(igraph_vector_ptr_push_back(res, cl));             \+            IGRAPH_CHECK(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_CALLBACK+#define RESTYPE \+    igraph_clique_handler_t *cliquehandler_fn, \+    void *arg+#define RESNAME cliquehandler_fn, arg+#define SUFFIX _callback+#define RECORD do { \+        igraph_vector_t *cl=igraph_Calloc(1, igraph_vector_t); \+        long j; \+        if (!cl) { \+            IGRAPH_ERROR("Cannot list maximal cliques", IGRAPH_ENOMEM); \+        } \+        IGRAPH_CHECK(igraph_vector_init(cl, clsize)); \+        for (j=0; j<clsize; j++) { VECTOR(*cl)[j] = VECTOR(*R)[j]; } \+        if (!cliquehandler_fn(cl, arg)) \+            return IGRAPH_STOP; \+    } while (0)+#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_HIST+#define RESTYPE igraph_vector_t *hist+#define RESNAME hist+#define SUFFIX _hist+#define RECORD do { \+        long hsize = igraph_vector_size(hist); \+        if (clsize > hsize) { \+            long hcapacity = igraph_vector_capacity(hist); \+            long j; \+            int err; \+            if (hcapacity < clsize && clsize < 2*hcapacity) \+                err = igraph_vector_reserve(hist, 2*hcapacity); \+            err = igraph_vector_resize(hist, clsize); \+            if (err != IGRAPH_SUCCESS) \+                IGRAPH_ERROR("Cannot count maximal cliques", IGRAPH_ENOMEM); \+            for (j=hsize; j < clsize; j++) \+                VECTOR(*hist)[j] = 0; \+        } \+        VECTOR(*hist)[clsize-1] += 1; \+    } while (0)+#define FINALLY \+    igraph_vector_clear(hist); \+    igraph_vector_reserve(hist, 50); /* initially reserve space for 50 elements */+#define FOR_LOOP_OVER_VERTICES for (i=0; i<no_of_nodes; i++) {+#define FOR_LOOP_OVER_VERTICES_PREPARE+#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) {++    int err;++    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 */+            err = FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)(+                      PX, newPS, PE, XS, newXE, PS, XE, R,+                      pos, adjlist, RESNAME, nextv, H,+                      min_size, max_size);++            if (err == IGRAPH_STOP) {+                return err;+            } else {+                IGRAPH_CHECK(err);+            }+            /* 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;+    int err;+    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);++    err = FUNCTION(igraph_i_maximal_cliques_bk, SUFFIX)(+              &PX, PS, PE, XS, XE, PS, XE, &R, &pos,+              &adjlist, RESNAME, &nextv, &H, min_size,+              max_size);+    if (err == IGRAPH_STOP) {+        break;+    } else {+        IGRAPH_CHECK(err);+    }+}++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
+ igraph/include/plfit/arithmetic_ansi.h view
@@ -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);+}
+ igraph/include/plfit/arithmetic_sse_double.h view
@@ -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); \+}
+ igraph/include/plfit/arithmetic_sse_float.h view
@@ -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); \+}
+ igraph/include/plfit/error.h view
@@ -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__ */
+ igraph/include/plfit/gss.h view
@@ -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__ */
+ igraph/include/plfit/kolmogorov.h view
@@ -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
+ igraph/include/plfit/lbfgs.h view
@@ -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*/++++/**+@mainpage libLBFGS: a library of Limited-memory Broyden-Fletcher-Goldfarb-Shanno (L-BFGS)++@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>++@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>.++@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.++@section api Documentation++- @ref liblbfgs_api "libLBFGS API"++@section sample Sample code++@include sample.c++@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.++@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__*/
+ igraph/include/plfit/platform.h view
@@ -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__ */
+ igraph/include/plfit/plfit.h view
@@ -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__ */+
+ igraph/include/plfit/zeta.h view
@@ -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__ */+
+ igraph/include/pottsmodel_2.h view
@@ -0,0 +1,167 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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
+ igraph/include/prpack.h view
@@ -0,0 +1,54 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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+
+ igraph/include/prpack/prpack.h view
@@ -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
+ igraph/include/prpack/prpack_base_graph.h view
@@ -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
+ igraph/include/prpack/prpack_csc.h view
@@ -0,0 +1,30 @@+#ifndef PRPACK_CSC+#define PRPACK_CSC++#if !defined(_MSC_VER) && !defined (__MINGW32__) && !defined (__MINGW64__)+#  include <stdint.h>+#else+#  include <stdio.h>+typedef __int64 int64_t;+#endif++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
+ igraph/include/prpack/prpack_csr.h view
@@ -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
+ igraph/include/prpack/prpack_edge_list.h view
@@ -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
+ igraph/include/prpack/prpack_igraph_graph.h view
@@ -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
+ igraph/include/prpack/prpack_preprocessed_ge_graph.h view
@@ -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
+ igraph/include/prpack/prpack_preprocessed_graph.h view
@@ -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
+ igraph/include/prpack/prpack_preprocessed_gs_graph.h view
@@ -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
+ igraph/include/prpack/prpack_preprocessed_scc_graph.h view
@@ -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
+ igraph/include/prpack/prpack_preprocessed_schur_graph.h view
@@ -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
+ igraph/include/prpack/prpack_result.h view
@@ -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
+ igraph/include/prpack/prpack_solver.h view
@@ -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
+ igraph/include/prpack/prpack_utils.h view
@@ -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+
+ igraph/include/scg_headers.h view
@@ -0,0 +1,128 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@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@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
+ igraph/include/stack.pmt view
@@ -0,0 +1,294 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "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.+ *+ * Reserve 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+
+ igraph/include/structural_properties_internal.h view
@@ -0,0 +1,47 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2016  Gabor Csardi <csardi.gabor@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 STRUCTURAL_PROPERTIES_INTERNAL_H+#define STRUCTURAL_PROPERTIES_INTERNAL_H++#include "igraph_constants.h"+#include "igraph_types.h"+#include "igraph_iterators.h"++int igraph_i_induced_subgraph_suggest_implementation(+    const igraph_t *graph, const igraph_vs_t vids,+    igraph_subgraph_implementation_t* result+);++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);++#endif
+ igraph/include/triangles_template.h view
@@ -0,0 +1,118 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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;+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);++#ifndef TRIANGLES+    IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));+    igraph_vector_null(res);+#else+    igraph_vector_int_clear(res);+#endif++for (nn = no_of_nodes - 1; nn >= 0; nn--) {+    node = VECTOR(order)[nn];++    IGRAPH_ALLOW_INTERRUPTION();++    neis1 = igraph_adjlist_get(&allneis, node);+    neilen1 = igraph_vector_int_size(neis1);+    deg1 = (long int) VECTOR(degree)[node];+    /* 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) {+#ifndef TRIANGLES+                VECTOR(*res)[nei2] += 1;+                VECTOR(*res)[nei] += 1;+                VECTOR(*res)[node] += 1;+#else+                IGRAPH_CHECK(igraph_vector_int_push_back(res, node));+                IGRAPH_CHECK(igraph_vector_int_push_back(res, nei));+                IGRAPH_CHECK(igraph_vector_int_push_back(res, nei2));+#endif+            }+        }+    }++#ifdef TRANSIT+    if (mode == IGRAPH_TRANSITIVITY_ZERO && deg1 < 2) {+        VECTOR(*res)[node] = 0.0;+    } else {+        VECTOR(*res)[node] = VECTOR(*res)[node] / deg1 / (deg1 - 1) * 2.0;+    }+#endif+#ifdef TRIEDGES+    VECTOR(*res)[node] += deg1;+#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);
+ igraph/include/triangles_template1.h view
@@ -0,0 +1,88 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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;+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;+    }+    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 && neilen1 < 2) {+        VECTOR(*res)[i] = 0.0;+    } else {+        VECTOR(*res)[i] = triangles / neilen1 / (neilen1 - 1);+    }+#else+    VECTOR(*res)[i] = triangles / 2;+#endif+}++igraph_lazy_adjlist_destroy(&adjlist);+igraph_Free(neis);+igraph_vit_destroy(&vit);+IGRAPH_FINALLY_CLEAN(3);
+ igraph/include/vector.pmt view
@@ -0,0 +1,2684 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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. It may not be \c NULL.+ * \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;++    assert(data != 0);++    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(&amp;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(&amp;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,+                                       const 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.+ */++igraph_real_t 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;+    igraph_real_t diff = 0.0;++    for (i = 0; i < n; i++) {+        igraph_real_t d = fabs((igraph_real_t)(VECTOR(*m1)[i]) -+                               (igraph_real_t)(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 &amp; 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;+}
+ igraph/include/walktrap_communities.h view
@@ -0,0 +1,176 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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@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
+ igraph/include/walktrap_graph.h view
@@ -0,0 +1,108 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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@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+
+ igraph/include/walktrap_heap.h view
@@ -0,0 +1,134 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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@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+
+ igraph/src/DensityGrid.cpp view
@@ -0,0 +1,284 @@+/*+ * 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);+        return;+#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;++    // check to see that we are inside grid+    if ( (x_grid >= GRID_SIZE) || (x_grid < 0) ||+         (y_grid >= GRID_SIZE) || (y_grid < 0) ) {+#ifdef MUSE_MPI+        MPI_Abort ( MPI_COMM_WORLD, 1 );+#else+        igraph_error("Exceeded density grid in DrL", __FILE__,+                     __LINE__, IGRAPH_EDRL);+        return;+#endif+    }++    /* 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) ) {+#ifdef MUSE_MPI+        MPI_Abort ( MPI_COMM_WORLD, 1 );+#else+        igraph_error("Exceeded density grid in DrL", __FILE__,+                     __LINE__, IGRAPH_EDRL);+        return;+#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
+ igraph/src/DensityGrid_3d.cpp view
@@ -0,0 +1,308 @@+/*+ * 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);+        return;+#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;++    // 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) ) {+#ifdef MUSE_MPI+        MPI_Abort ( MPI_COMM_WORLD, 1 );+#else+        igraph_error("Exceeded density grid in DrL", __FILE__,+                     __LINE__, IGRAPH_EDRL);+        return;+#endif+    }++    /* 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) ) {+#ifdef MUSE_MPI+        MPI_Abort ( MPI_COMM_WORLD, 1 );+#else+        igraph_error("Exceeded density grid in DrL", __FILE__,+                     __LINE__, IGRAPH_EDRL);+        return;+#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
+ igraph/src/NetDataTypes.cpp view
@@ -0,0 +1,222 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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);+    }+}
+ igraph/src/NetRoutines.cpp view
@@ -0,0 +1,286 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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();+    }+}+
+ igraph/src/abort_.c view
@@ -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
+ igraph/src/adjlist.c view
@@ -0,0 +1,930 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}++#define ADJLIST_CANON_EDGE(from, to, directed) \+    do {                     \+        igraph_integer_t temp;         \+        if((!directed) && from < to) {     \+            temp = to;               \+            to = from;               \+            from = temp;             \+        }                      \+    } while(0);++igraph_bool_t igraph_adjlist_has_edge(igraph_adjlist_t* al, igraph_integer_t from, igraph_integer_t to, igraph_bool_t directed) {+    igraph_vector_int_t* fromvec;+    ADJLIST_CANON_EDGE(from, to, directed);+    fromvec = igraph_adjlist_get(al, from);+    return igraph_vector_int_binsearch2(fromvec, to);++}++int igraph_adjlist_replace_edge(igraph_adjlist_t* al, igraph_integer_t from, igraph_integer_t oldto, igraph_integer_t newto, igraph_bool_t directed) {+    igraph_vector_int_t *oldfromvec, *newfromvec;+    int err1, err2;+    long int oldpos, newpos;+    igraph_integer_t oldfrom = from, newfrom = from;+    ADJLIST_CANON_EDGE(oldfrom, oldto, directed);+    ADJLIST_CANON_EDGE(newfrom, newto, directed);++    oldfromvec = igraph_adjlist_get(al, oldfrom);+    newfromvec = igraph_adjlist_get(al, newfrom);+++    err1 = igraph_vector_int_binsearch(oldfromvec, oldto, &oldpos);+    err2 = igraph_vector_int_binsearch(newfromvec, newto, &newpos);++    /* oldfrom -> oldto should exist; newfrom -> newto should not. */+    if ((!err1) || err2) {+        return 1;+    }++    igraph_vector_int_remove(oldfromvec, oldpos);+    if (oldfromvec == newfromvec && oldpos < newpos) {+        --newpos;+    }+    IGRAPH_CHECK(igraph_vector_int_insert(newfromvec, newpos, newto));++    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_int_t *v = &al->incs[i];+        long int j, p = 1, l = igraph_vector_int_size(v);+        for (j = 1; j < l; j++) {+            long int e = (long int) VECTOR(*v)[j];+            /* Non-loop edges and one end of loop edges are fine. */+            /* We use here, that the vector is sorted and we also keep it sorted */+            if (IGRAPH_FROM(graph, e) != IGRAPH_TO(graph, e) ||+                VECTOR(*v)[j - 1] != e) {+                VECTOR(*v)[p++] = e;+            }+        }+        igraph_vector_int_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_int_t *v = &al->incs[i];+        igraph_vector_int_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_int_t *v = &al->incs[i];+        igraph_vector_int_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;+    igraph_vector_t tmp;++    if (mode != IGRAPH_IN && mode != IGRAPH_OUT && mode != IGRAPH_ALL) {+        IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_EINVMODE);+    }++    igraph_vector_init(&tmp, 0);+    IGRAPH_FINALLY(igraph_vector_destroy, &tmp);++    if (!igraph_is_directed(graph)) {+        mode = IGRAPH_ALL;+    }++    il->length = igraph_vcount(graph);+    il->incs = igraph_Calloc(il->length, igraph_vector_int_t);+    if (il->incs == 0) {+        IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_ENOMEM);+    }++    IGRAPH_FINALLY(igraph_inclist_destroy, il);+    for (i = 0; i < il->length; i++) {+        int j, n;+        IGRAPH_ALLOW_INTERRUPTION();+        IGRAPH_CHECK(igraph_incident(graph, &tmp, i, mode));+        n = igraph_vector_size(&tmp);+        IGRAPH_CHECK(igraph_vector_int_init(&il->incs[i], n));+        for (j = 0; j < n; j++) {+            VECTOR(il->incs[i])[j] = VECTOR(tmp)[j];+        }+    }++    igraph_vector_destroy(&tmp);+    IGRAPH_FINALLY_CLEAN(2);+    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_int_t);+    if (il->incs == 0) {+        IGRAPH_ERROR("Cannot create incidence list view", IGRAPH_ENOMEM);+    }++    IGRAPH_FINALLY(igraph_inclist_destroy, il);+    for (i = 0; i < n; i++) {+        IGRAPH_CHECK(igraph_vector_int_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_int_t's are 0,+           because igraph_vector_destroy can handle this. */+        igraph_vector_int_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_int_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];+}
+ igraph/src/arithchk.c view
@@ -0,0 +1,262 @@+/****************************************************************+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;+	}++/* avoid possible warning message with printf("") */+const char *const emptyfmt = "";++#ifdef __GNUC__+#  pragma GCC diagnostic push+#  ifndef __clang__+#    pragma GCC diagnostic ignored "-Wformat-security"+#    pragma GCC diagnostic ignored "-Wunused-but-set-variable"+#  else+#    pragma GCC diagnostic ignored "-Wformat-zero-length"+#  endif+#endif++ 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;+	}++#ifdef __GNUC__+#  ifndef __clang__+#    pragma GCC diagnostic pop+#  endif+#endif++ 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
+ igraph/src/arpack.c view
@@ -0,0 +1,1429 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 noet: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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, i;+    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 nc = 0, nr = 0, ncol, 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;++            idx = (unsigned int) VECTOR(order)[i];++            if (di[i] == 0) {+                /* real eigenvalue, single eigenvector */+                memcpy(&MATRIX(*vectors, 0, vx), v + n * idx, sizeof(igraph_real_t) * n);+                vx++;+            } else if (di[i] > 0) {+                /* complex eigenvalue, positive imaginary part encountered first.+                 * ARPACK stores its eigenvector directly in two consecutive columns.+                 * The complex conjugate pair of the eigenvalue (if any) will be in+                 * the next column and we will skip it because we advance 'i' below */+                memcpy(&MATRIX(*vectors, 0, vx), v + n * idx, sizeof(igraph_real_t) * 2 * n);+                vx += 2;+                i++;+            } else {+                /* complex eigenvalue, negative imaginary part encountered first.+                     * The positive one will be the next one, but we need to copy the+                     * eigenvector corresponding to the eigenvalue with the positive+                     * imaginary part. */+                idx = (unsigned int) VECTOR(order)[i + 1];+                memcpy(&MATRIX(*vectors, 0, vx), v + n * idx, sizeof(igraph_real_t) * 2 * n);+                vx += 2;+                i++;+            }+        }+    }++    igraph_vector_destroy(&order);+    IGRAPH_FINALLY_CLEAN(1);++    if (values) {+        /* Strive to include complex conjugate eigenvalue pairs in a way that the+         * positive imaginary part comes first */+        for (i = 0; i < nans; i++) {+            if (MATRIX(*values, i, 1) == 0) {+                /* Real eigenvalue, nothing to do */+            } else if (MATRIX(*values, i, 1) < 0) {+                /* Negative imaginary part came first; negate the imaginary part for+                 * this eigenvalue and the next one (which is the complex conjugate+                 * pair), and skip it */+                MATRIX(*values, i, 1) *= -1;+                i++;+                if (i < nans) {+                    MATRIX(*values, i, 1) *= -1;+                }+            } else {+                /* Positive imaginary part; skip the next eigenvalue, which is the+                 * complex conjugate pair */+                i++;+            }+        }+    }++    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 */+    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 in mode 1 */+    if (options->mode == 1 && options->n == 1) {+        return igraph_i_arpack_rssolve_1x1(fun, extra, options, values, vectors);+    } else if (options->mode == 1 && 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->bmat[0] = 'I';+    options->iparam[0] = options->ishift;+    options->iparam[1] = 0;   // not referenced+    options->iparam[2] = options->mxiter;+    options->iparam[3] = 1;   // currently dsaupd() works only for nb=1+    options->iparam[4] = 0;+    options->iparam[5] = 0;   // not referenced+    options->iparam[6] = options->mode;+    options->iparam[7] = 0;   // return value+    options->iparam[8] = 0;   // return value+    options->iparam[9] = 0;   // return value+    options->iparam[10] = 0;  // return value+    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.+ *     Note that real eigenvalues will have real eigenvectors in a single+ *     column in this matrix; however, complex eigenvalues come in conjugate+ *     pairs and the result matrix will store the eigenvector corresponding to+ *     the eigenvalue with \em positive imaginary part only. Since in this case+ *     the eigenvector is also complex, it will occupy \em two columns in the+ *     eigenvector matrix (the real and the imaginary parts, in this order).+ *     Caveat: if the eigenvalue vector returns only the eigenvalue with the+ *     \em negative imaginary part for a complex conjugate eigenvalue pair, the+ *     result vector will \em still store the eigenvector corresponding to the+ *     eigenvalue with the positive imaginary part (since this is how ARPACK+ *     works).+ * \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 in mode 1 */+    if (options->mode == 1 && options->n == 1) {+        return igraph_i_arpack_rnsolve_1x1(fun, extra, options, values, vectors);+    } else if (options->mode == 1 && 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->bmat[0] = 'I';+    options->iparam[0] = options->ishift;+    options->iparam[1] = 0;   // not referenced+    options->iparam[2] = options->mxiter;+    options->iparam[3] = 1;   // currently dnaupd() works only for nb=1+    options->iparam[4] = 0;+    options->iparam[5] = 0;   // not referenced+    options->iparam[6] = options->mode;+    options->iparam[7] = 0;   // return value+    options->iparam[8] = 0;   // return value+    options->iparam[9] = 0;   // return value+    options->iparam[10] = 0;  // return value+    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 && options->info != -9999) {+        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");+    }++    /* ARPACK might modify stuff in 'options' so reset everything that could+     * potentially get modified */+    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;++    if (values || vectors) {+        IGRAPH_CHECK(igraph_arpack_rnsort(values, vectors, options,+                                          dr, di, v));+    }++    /* 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;+}
+ igraph/src/array.c view
@@ -0,0 +1,50 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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
+ igraph/src/atlas.c view
@@ -0,0 +1,82 @@+/* -*- mode: C -*-  */+/*+   IGraph R package.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 &lt; 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;+}
+ igraph/src/attributes.c view
@@ -0,0 +1,442 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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,+                                     igraph_function_pointer_t 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,+                                       igraph_function_pointer_t *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) {+        igraph_function_pointer_t 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) {+#if defined(__GNUC__)+            func = va_arg(ap, void (*)(void));+#else+            func = va_arg(ap, void*);+#endif+        }++        if (strlen(name) == 0) {+            name = 0;+        }++        IGRAPH_CHECK(igraph_attribute_combination_add(comb, name, type, func));+    }++    va_end(ap);++    return 0;+}
+ igraph/src/backspac.c view
@@ -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
+ igraph/src/basic_query.c view
@@ -0,0 +1,64 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/bfgs.c view
@@ -0,0 +1,223 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/bigint.c view
@@ -0,0 +1,329 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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"++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;+}+
+ igraph/src/bignum.c view
@@ -0,0 +1,1984 @@+/******************************************************************************+ * bn.c - big number math implementation+ *+ * Copyright (c) 2004 by Juergen Buchmueller <pullmoll@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;+}
+ igraph/src/bipartite.c view
@@ -0,0 +1,1147 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2008-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 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.+ * \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 probe1 This argument can be used to specify the order of the+ *   projections in the resulting list. When it is non-negative, then+ *   it is considered as a vertex ID and the projection containing+ *   this vertex will be the first one in the result. Setting this+ *   argument to a non-negative value implies that \c proj1 must be+ *   a non-null pointer. If you don't care about the ordering of the+ *   projections, pass -1 here.+ * \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 = (double) n1 * (double) n2;+        } else {+            maxedges = 2.0 * (double) n1 * (double) 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) {+        if (m > 0) {+            IGRAPH_ERROR("Invalid number (too large) of edges", IGRAPH_EINVAL);+        }+        IGRAPH_CHECK(retval = igraph_empty(graph, n1 + n2, directed));+    } else {+++        long int i;+        double maxedges;+        if (!directed || mode != IGRAPH_ALL) {+            maxedges = (double) n1 * (double) n2;+        } else {+            maxedges = 2.0 * (double) n1 * (double) 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;+}
+ igraph/src/blas.c view
@@ -0,0 +1,110 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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);+}++igraph_real_t igraph_blas_dnrm2(const igraph_vector_t *v) {+    int n = igraph_vector_size(v);+    int one = 1;+    return igraphdnrm2_(&n, VECTOR(*v), &one);+}
+ igraph/src/bliss.cc view
@@ -0,0 +1,262 @@+/*+ 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/graph.hh"++#include "igraph_types.h"+#include "igraph_topology.h"++#include "igraph_datatype.h"+#include "igraph_interface.h"+++using namespace bliss;+using namespace std;+++namespace { // unnamed namespace++inline AbstractGraph *bliss_from_igraph(const igraph_t *graph) {+    unsigned int nof_vertices = (unsigned int)igraph_vcount(graph);+    unsigned int nof_edges = (unsigned int)igraph_ecount(graph);++    AbstractGraph *g;++    if (igraph_is_directed(graph)) {+        g = new Digraph(nof_vertices);+    } else {+        g = new Graph(nof_vertices);+    }++    g->set_verbose_level(0);++    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 bliss_free_graph(AbstractGraph *g) {+    delete g;+}+++inline int bliss_set_sh(AbstractGraph *g, igraph_bliss_sh_t sh, bool directed) {+    if (directed) {+        Digraph::SplittingHeuristic gsh = Digraph::shs_fsm;+        switch (sh) {+        case IGRAPH_BLISS_F:    gsh = Digraph::shs_f;   break;+        case IGRAPH_BLISS_FL:   gsh = Digraph::shs_fl;  break;+        case IGRAPH_BLISS_FS:   gsh = Digraph::shs_fs;  break;+        case IGRAPH_BLISS_FM:   gsh = Digraph::shs_fm;  break;+        case IGRAPH_BLISS_FLM:  gsh = Digraph::shs_flm; break;+        case IGRAPH_BLISS_FSM:  gsh = Digraph::shs_fsm; break;+        default: IGRAPH_ERROR("Invalid splitting heuristic", IGRAPH_EINVAL);+        }+        static_cast<Digraph *>(g)->set_splitting_heuristic(gsh);+    } else {+        Graph::SplittingHeuristic gsh = Graph::shs_fsm;+        switch (sh) {+        case IGRAPH_BLISS_F:    gsh = Graph::shs_f;   break;+        case IGRAPH_BLISS_FL:   gsh = Graph::shs_fl;  break;+        case IGRAPH_BLISS_FS:   gsh = Graph::shs_fs;  break;+        case IGRAPH_BLISS_FM:   gsh = Graph::shs_fm;  break;+        case IGRAPH_BLISS_FLM:  gsh = Graph::shs_flm; break;+        case IGRAPH_BLISS_FSM:  gsh = Graph::shs_fsm; break;+        default: IGRAPH_ERROR("Invalid splitting heuristic", IGRAPH_EINVAL);+        }+        static_cast<Graph *>(g)->set_splitting_heuristic(gsh);+    }+    return IGRAPH_SUCCESS;+}+++inline int bliss_set_colors(AbstractGraph *g, const igraph_vector_int_t *colors) {+    if (colors == NULL) {+        return IGRAPH_SUCCESS;+    }+    const int n = g->get_nof_vertices();+    if (n != igraph_vector_int_size(colors)) {+        IGRAPH_ERROR("Invalid vertex color vector length", IGRAPH_EINVAL);+    }+    for (int i = 0; i < n; ++i) {+        g->change_color(i, VECTOR(*colors)[i]);+    }+    return IGRAPH_SUCCESS;+}+++inline void bliss_info_to_igraph(igraph_bliss_info_t *info, const Stats &stats) {+    if (info) {+        info->max_level      = stats.get_max_level();+        info->nof_nodes      = stats.get_nof_nodes();+        info->nof_leaf_nodes = stats.get_nof_leaf_nodes();+        info->nof_bad_nodes  = stats.get_nof_bad_nodes();+        info->nof_canupdates = stats.get_nof_canupdates();+        info->nof_generators = stats.get_nof_generators();+        stats.group_size.tostring(&info->group_size);+    }+}+++// this is the callback function used with AbstractGraph::find_automorphisms()+// it collects the group generators into a pointer vector+void collect_generators(void *generators, unsigned int n, const unsigned int *aut) {+    igraph_vector_ptr_t *gen = static_cast<igraph_vector_ptr_t *>(generators);+    igraph_vector_t *newvector = igraph_Calloc(1, igraph_vector_t);+    igraph_vector_init(newvector, n);+    copy(aut, aut + n, newvector->stor_begin); // takes care of unsigned int -> double conversion+    igraph_vector_ptr_push_back(gen, newvector);+}++} // end unnamed namespace++/**+ * \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. Multiple edges between the same nodes+ *   are not supported and will cause an incorrect result to be returned.+ * \param colors An optional vertex color vector for the graph. Supply a+ *   null pointer is the graph is not colored.+ * \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 splitting 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, const igraph_vector_int_t *colors,+                                 igraph_vector_t *labeling, igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {+    AbstractGraph *g = bliss_from_igraph(graph);+    IGRAPH_FINALLY(bliss_free_graph, g);+    const unsigned int N = g->get_nof_vertices();++    IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));+    IGRAPH_CHECK(bliss_set_colors(g, colors));++    Stats stats;+    const unsigned int *cl = g->canonical_form(stats, NULL, NULL);+    IGRAPH_CHECK(igraph_vector_resize(labeling, N));+    for (unsigned int i = 0; i < N; i++) {+        VECTOR(*labeling)[i] = cl[i];+    }++    bliss_info_to_igraph(info, stats);++    delete g;+    IGRAPH_FINALLY_CLEAN(1);+    return IGRAPH_SUCCESS;+}++/**+ * \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. Multiple edges between the same nodes+ *   are not supported and will cause an incorrect result to be returned.+ * \param colors An optional vertex color vector for the graph. Supply a+ *   null pointer is the graph is not colored.+ * \param sh The splitting 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, const igraph_vector_int_t *colors,+                         igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {+    AbstractGraph *g = bliss_from_igraph(graph);+    IGRAPH_FINALLY(bliss_free_graph, g);++    IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));+    IGRAPH_CHECK(bliss_set_colors(g, colors));++    Stats stats;+    g->find_automorphisms(stats, NULL, NULL);++    bliss_info_to_igraph(info, stats);++    delete g;+    IGRAPH_FINALLY_CLEAN(1);+    return IGRAPH_SUCCESS;+}++/**+ * \function igraph_automorphism_group+ * Automorphism group generators using BLISS+ *+ * The generators of the automorphism group of a graph are computed+ * using BLISS. The generator set may not be minimal and may depend on+ * the splitting heuristics.+ *+ * \param graph The input graph. Multiple edges between the same nodes+ *   are not supported and will cause an incorrect result to be returned.+ * \param colors An optional vertex color vector for the graph. Supply a+ *   null pointer is the graph is not colored.+ * \param generators Must be an initialized pointer vector. It will+ *    contain pointers to \ref igraph_vector_t objects+ *    representing generators of the automorphism group.+ * \param sh The splitting 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_automorphism_group(+    const igraph_t *graph, const igraph_vector_int_t *colors, igraph_vector_ptr_t *generators,+    igraph_bliss_sh_t sh, igraph_bliss_info_t *info) {+    AbstractGraph *g = bliss_from_igraph(graph);+    IGRAPH_FINALLY(bliss_free_graph, g);++    IGRAPH_CHECK(bliss_set_sh(g, sh, igraph_is_directed(graph)));+    IGRAPH_CHECK(bliss_set_colors(g, colors));++    Stats stats;+    igraph_vector_ptr_resize(generators, 0);+    g->find_automorphisms(stats, collect_generators, generators);++    bliss_info_to_igraph(info, stats);++    delete g;+    IGRAPH_FINALLY_CLEAN(1);+    return IGRAPH_SUCCESS;+}+++
+ igraph/src/bliss_heap.cc view
@@ -0,0 +1,99 @@+#include <stdlib.h>+#include <stdio.h>+#include <limits.h>+#include "defs.hh"+#include "heap.hh"++/* use 'and' instead of '&&' */+#if _MSC_VER+#include <ciso646>+#endif++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++Heap::~Heap()+{+  if(array)+    {+      free(array);+      array = 0;+      n = 0;+      N = 0;+    }+}++void Heap::upheap(unsigned int index)+{+  const unsigned int v = array[index];+  array[0] = 0;+  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];+  const unsigned int lim = n/2;+  while(index <= lim)+    {+      unsigned int new_index = index + index;+      if((new_index < n) and (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(const unsigned int size)+{+  if(size > N)+    {+      if(array)+	free(array);+      array = (unsigned int*)malloc((size + 1) * sizeof(unsigned int));+      N = size;+    }+  n = 0;+}++void Heap::insert(const unsigned int v)+{+  array[++n] = v;+  upheap(n);+}++unsigned int Heap::remove()+{+  const unsigned int v = array[1];+  array[1] = array[n--];+  downheap(1);+  return v;+}++} // namespace bliss
+ igraph/src/c_abs.c view
@@ -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
+ igraph/src/c_cos.c view
@@ -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
+ igraph/src/c_div.c view
@@ -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
+ igraph/src/c_exp.c view
@@ -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
+ igraph/src/c_log.c view
@@ -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
+ igraph/src/c_sin.c view
@@ -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
+ igraph/src/c_sqrt.c view
@@ -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
+ igraph/src/cabs.c view
@@ -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
+ igraph/src/cattributes.c view
@@ -0,0 +1,4211 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+    } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {+        igraph_vector_bool_t *log = (igraph_vector_bool_t*) rec->value;+        igraph_vector_bool_t *newlog = igraph_Calloc(1, igraph_vector_bool_t);+        if (!newlog) {+            IGRAPH_ERROR("Cannot copy attributes", IGRAPH_ENOMEM);+        }+        IGRAPH_FINALLY(igraph_free, newlog);+        IGRAPH_CHECK(igraph_vector_bool_copy(newlog, log));+        IGRAPH_FINALLY(igraph_vector_bool_destroy, newlog);+        (*newrec)->value = newlog;+    }++    IGRAPH_FINALLY_CLEAN(4);+    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_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) {+                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_BOOLEAN) {+                boolvec = (igraph_vector_bool_t*)rec->value;+                igraph_vector_bool_destroy(boolvec);+                igraph_free(boolvec);+            } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+                str = (igraph_strvector_t*)rec->value;+                igraph_strvector_destroy(str);+                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;+            } else if (type == IGRAPH_ATTRIBUTE_BOOLEAN) {+                igraph_vector_bool_t *newbool = igraph_Calloc(1, igraph_vector_bool_t);+                if (!newbool) {+                    IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+                }+                IGRAPH_FINALLY(igraph_free, newbool);+                IGRAPH_CHECK(igraph_vector_bool_init(newbool, origlen));+                IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);+                newrec->value = newbool;+                igraph_vector_bool_fill(newbool, 0);+            }+            IGRAPH_CHECK(igraph_vector_ptr_push_back(val, newrec));+            IGRAPH_FINALLY_CLEAN(4);+        }+        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;+            igraph_vector_bool_t *oldbool, *newbool;+            newrec = VECTOR(*nattr)[j];+            oldnum = (igraph_vector_t*)oldrec->value;+            newnum = (igraph_vector_t*)newrec->value;+            oldstr = (igraph_strvector_t*)oldrec->value;+            newstr = (igraph_strvector_t*)newrec->value;+            oldbool = (igraph_vector_bool_t*)oldrec->value;+            newbool = (igraph_vector_bool_t*)newrec->value;+            if (oldrec->type != newrec->type) {+                IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);+            }+            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;+            case IGRAPH_ATTRIBUTE_BOOLEAN:+                if (nv != igraph_vector_bool_size(newbool)) {+                    IGRAPH_ERROR("Invalid Boolean attribute length", IGRAPH_EINVAL);+                }+                IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool));+                break;+            default:+                IGRAPH_WARNING("Invalid attribute type");+                break;+            }+        } 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;+            igraph_vector_bool_t *oldbool = (igraph_vector_bool_t*)oldrec->value;+            switch (oldrec->type) {+            case IGRAPH_ATTRIBUTE_NUMERIC:+                IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen + nv));+                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;+            case IGRAPH_ATTRIBUTE_BOOLEAN:+                IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen + nv));+                for (j = origlen; j < origlen + nv; j++) {+                    VECTOR(*oldbool)[j] = 0;+                }+                break;+            default:+                IGRAPH_WARNING("Invalid attribute type");+                break;+            }+        }+    }++    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);+        } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {+            igraph_vector_bool_t *boolv = (igraph_vector_bool_t*) rec->value;+            igraph_vector_bool_destroy(boolv);+            igraph_Free(boolv);+        }+        igraph_Free(rec);+    }+    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;+            igraph_vector_bool_t *oldbool, *newbool;+            switch (type) {+            case IGRAPH_ATTRIBUTE_NUMERIC:+                num = (igraph_vector_t*) oldrec->value;+                newnum = igraph_Calloc(1, igraph_vector_t);+                if (!newnum) {+                    IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);+                }+                IGRAPH_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_BOOLEAN:+                oldbool = (igraph_vector_bool_t*) oldrec->value;+                newbool = igraph_Calloc(1, igraph_vector_bool_t);+                if (!newbool) {+                    IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);+                }+                IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));+                IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);+                igraph_vector_bool_index(oldbool, newbool, idx);+                oldrec->value = newbool;+                igraph_vector_bool_destroy(oldbool);+                igraph_Free(oldbool);+                IGRAPH_FINALLY_CLEAN(1);+                break;+            case IGRAPH_ATTRIBUTE_STRING:+                str = (igraph_strvector_t*)oldrec->value;+                newstr = igraph_Calloc(1, igraph_strvector_t);+                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;+            igraph_vector_bool_t *oldbool, *newbool;++            /* 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_BOOLEAN:+                oldbool = (igraph_vector_bool_t*)oldrec->value;+                newbool = igraph_Calloc(1, igraph_vector_bool_t);+                if (!newbool) {+                    IGRAPH_ERROR("Cannot permute vertex attributes", IGRAPH_ENOMEM);+                }+                IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));+                IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);+                igraph_vector_bool_index(oldbool, newbool, idx);+                new_rec->value = newbool;+                IGRAPH_FINALLY_CLEAN(1);+                break;+            case IGRAPH_ATTRIBUTE_STRING:+                str = (igraph_strvector_t*)oldrec->value;+                newstr = igraph_Calloc(1, igraph_strvector_t);+                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;+}++typedef int igraph_cattributes_combine_num_t(const igraph_vector_t *input,+        igraph_real_t *output);++typedef int igraph_cattributes_combine_str_t(const igraph_strvector_t *input,+        char **output);++typedef int igraph_cattributes_combine_bool_t(const igraph_vector_bool_t *input,+        igraph_bool_t *output);++int igraph_i_cattributes_cn_sum(const igraph_attribute_record_t *oldrec,+                                igraph_attribute_record_t * newrec,+                                const igraph_vector_ptr_t *merges) {+    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;+}++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_cb_random(const igraph_attribute_record_t *oldrec,+                                   igraph_attribute_record_t * newrec,+                                   const igraph_vector_ptr_t *merges) {++    const igraph_vector_bool_t *oldv = oldrec->value;+    igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);+    long int newlen = igraph_vector_ptr_size(merges);+    long int i;++    if (!newv) {+        IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, newv);+    IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    RNG_BEGIN();++    for (i = 0; i < newlen; i++) {+        igraph_vector_t *idx = VECTOR(*merges)[i];+        long int n = igraph_vector_size(idx);+        if (n == 0) {+            VECTOR(*newv)[i] = 0;+        } else if (n == 1) {+            VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];+        } else {+            long int r = RNG_INTEGER(0, n - 1);+            VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[r] ];+        }+    }++    RNG_END();++    IGRAPH_FINALLY_CLEAN(2);+    newrec->value = newv;++    return 0;+}++int igraph_i_cattributes_cb_first(const igraph_attribute_record_t *oldrec,+                                  igraph_attribute_record_t * newrec,+                                  const igraph_vector_ptr_t *merges) {++    const igraph_vector_bool_t *oldv = oldrec->value;+    igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);+    long int newlen = igraph_vector_ptr_size(merges);+    long int i;++    if (!newv) {+        IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, newv);+    IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    for (i = 0; i < newlen; i++) {+        igraph_vector_t *idx = VECTOR(*merges)[i];+        long int n = igraph_vector_size(idx);+        if (n == 0) {+            VECTOR(*newv)[i] = 0;+        } else {+            VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[0] ];+        }+    }++    IGRAPH_FINALLY_CLEAN(2);+    newrec->value = newv;++    return 0;+}++int igraph_i_cattributes_cb_last(const igraph_attribute_record_t *oldrec,+                                 igraph_attribute_record_t * newrec,+                                 const igraph_vector_ptr_t *merges) {++    const igraph_vector_bool_t *oldv = oldrec->value;+    igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);+    long int newlen = igraph_vector_ptr_size(merges);+    long int i;++    if (!newv) {+        IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, newv);+    IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    for (i = 0; i < newlen; i++) {+        igraph_vector_t *idx = VECTOR(*merges)[i];+        long int n = igraph_vector_size(idx);+        if (n == 0) {+            VECTOR(*newv)[i] = 0;+        } else {+            VECTOR(*newv)[i] = VECTOR(*oldv)[ (long int) VECTOR(*idx)[n - 1] ];+        }+    }++    IGRAPH_FINALLY_CLEAN(2);+    newrec->value = newv;++    return 0;+}++int igraph_i_cattributes_cb_all_is_true(const igraph_attribute_record_t *oldrec,+                                        igraph_attribute_record_t * newrec,+                                        const igraph_vector_ptr_t *merges) {++    const igraph_vector_bool_t *oldv = oldrec->value;+    igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);+    long int newlen = igraph_vector_ptr_size(merges);+    long int i, j, n, x;++    if (!newv) {+        IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, newv);+    IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    for (i = 0; i < newlen; i++) {+        igraph_vector_t *idx = VECTOR(*merges)[i];+        n = igraph_vector_size(idx);+        VECTOR(*newv)[i] = 1;+        for (j = 0; j < n; j++) {+            x = (long int) VECTOR(*idx)[j];+            if (!VECTOR(*oldv)[x]) {+                VECTOR(*newv)[i] = 0;+                break;+            }+        }+    }++    IGRAPH_FINALLY_CLEAN(2);+    newrec->value = newv;++    return 0;+}++int igraph_i_cattributes_cb_any_is_true(const igraph_attribute_record_t *oldrec,+                                        igraph_attribute_record_t * newrec,+                                        const igraph_vector_ptr_t *merges) {++    const igraph_vector_bool_t *oldv = oldrec->value;+    igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);+    long int newlen = igraph_vector_ptr_size(merges);+    long int i, j, n, x;++    if (!newv) {+        IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, newv);+    IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    for (i = 0; i < newlen; i++) {+        igraph_vector_t *idx = VECTOR(*merges)[i];+        n = igraph_vector_size(idx);+        VECTOR(*newv)[i] = 0;+        for (j = 0; j < n; j++) {+            x = (long int) VECTOR(*idx)[j];+            if (VECTOR(*oldv)[x]) {+                VECTOR(*newv)[i] = 1;+                break;+            }+        }+    }++    IGRAPH_FINALLY_CLEAN(2);+    newrec->value = newv;++    return 0;+}++int igraph_i_cattributes_cb_majority(const igraph_attribute_record_t *oldrec,+                                     igraph_attribute_record_t * newrec,+                                     const igraph_vector_ptr_t *merges) {++    const igraph_vector_bool_t *oldv = oldrec->value;+    igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);+    long int newlen = igraph_vector_ptr_size(merges);+    long int i, j, n, x, num_trues;++    if (!newv) {+        IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, newv);+    IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    RNG_BEGIN();++    for (i = 0; i < newlen; i++) {+        igraph_vector_t *idx = VECTOR(*merges)[i];++        n = igraph_vector_size(idx);++        num_trues = 0;+        for (j = 0; j < n; j++) {+            x = (long int) VECTOR(*idx)[j];+            if (VECTOR(*oldv)[x]) {+                num_trues++;+            }+        }++        if (n % 2 != 0) {+            VECTOR(*newv)[i] = (num_trues > n / 2);+        } else {+            if (num_trues == n / 2) {+                VECTOR(*newv)[i] = (RNG_UNIF01() < 0.5);+            } else {+                VECTOR(*newv)[i] = (num_trues > n / 2);+            }+        }+    }++    RNG_END();++    IGRAPH_FINALLY_CLEAN(2);+    newrec->value = newv;++    return 0;+}++int igraph_i_cattributes_cb_func(const igraph_attribute_record_t *oldrec,+                                 igraph_attribute_record_t *newrec,+                                 const igraph_vector_ptr_t *merges,+                                 igraph_cattributes_combine_bool_t *func) {++    const igraph_vector_bool_t *oldv = oldrec->value;+    long int newlen = igraph_vector_ptr_size(merges);+    long int i;+    igraph_vector_bool_t *newv = igraph_Calloc(1, igraph_vector_bool_t);+    igraph_vector_bool_t values;++    if (!newv) {+        IGRAPH_ERROR("Cannot combine attributes", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, newv);+    IGRAPH_CHECK(igraph_vector_bool_init(newv, newlen));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    IGRAPH_CHECK(igraph_vector_bool_init(&values, 0));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, newv);++    for (i = 0; i < newlen; i++) {+        igraph_vector_t *idx = VECTOR(*merges)[i];+        long int j, n = igraph_vector_size(idx);+        igraph_bool_t res;++        IGRAPH_CHECK(igraph_vector_bool_resize(&values, n));+        for (j = 0; j < n; j++) {+            long int x = (long int) VECTOR(*idx)[j];+            VECTOR(values)[j] = VECTOR(*oldv)[x];+        }++        IGRAPH_CHECK(func(&values, &res));+        VECTOR(*newv)[i] = res;+    }++    igraph_vector_bool_destroy(&values);+    IGRAPH_FINALLY_CLEAN(3);+    newrec->value = newv;++    return 0;+}++int igraph_i_cattributes_sn_random(const igraph_attribute_record_t *oldrec,+                                   igraph_attribute_record_t *newrec,+                                   const igraph_vector_ptr_t *merges) {++    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;+    igraph_function_pointer_t *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, igraph_function_pointer_t);+    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;+        igraph_function_pointer_t 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];+        igraph_cattributes_combine_bool_t *boolfunc =+            (igraph_cattributes_combine_bool_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_BOOLEAN) {+            switch (todo) {+            case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:+                IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges,+                             boolfunc));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_SUM:+            case IGRAPH_ATTRIBUTE_COMBINE_MAX:+                IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_PROD:+            case IGRAPH_ATTRIBUTE_COMBINE_MIN:+                IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_MEAN:+            case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:+                IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:+                IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_FIRST:+                IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_LAST:+                IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:+                IGRAPH_ERROR("Cannot calculate concatenation of Booleans",+                             IGRAPH_EATTRCOMBINE);+                break;+            default:+                IGRAPH_ERROR("Unknown attribute_combination",+                             IGRAPH_UNIMPLEMENTED);+                break;+            }+        } else if (type == IGRAPH_ATTRIBUTE_STRING) {+            switch (todo) {+            case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:+                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_BOOLEAN) {+                igraph_vector_bool_t *newbool = igraph_Calloc(1, igraph_vector_bool_t);+                if (!newbool) {+                    IGRAPH_ERROR("Cannot add attributes", IGRAPH_ENOMEM);+                }+                IGRAPH_FINALLY(igraph_free, newbool);+                IGRAPH_CHECK(igraph_vector_bool_init(newbool, origlen));+                IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);+                newrec->value = newbool;+                igraph_vector_bool_fill(newbool, 0);+            } else if (type == IGRAPH_ATTRIBUTE_STRING) {+                igraph_strvector_t *newstr = igraph_Calloc(1, igraph_strvector_t);+                if (!newstr) {+                    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;+            igraph_vector_bool_t *oldbool, *newbool;+            newrec = VECTOR(*nattr)[j];+            oldnum = (igraph_vector_t*)oldrec->value;+            newnum = (igraph_vector_t*)newrec->value;+            oldstr = (igraph_strvector_t*)oldrec->value;+            newstr = (igraph_strvector_t*)newrec->value;+            oldbool = (igraph_vector_bool_t*)oldrec->value;+            newbool = (igraph_vector_bool_t*)newrec->value;+            if (oldrec->type != newrec->type) {+                IGRAPH_ERROR("Attribute types do not match", IGRAPH_EINVAL);+            }+            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;+            case IGRAPH_ATTRIBUTE_BOOLEAN:+                if (ne != igraph_vector_bool_size(newbool)) {+                    IGRAPH_ERROR("Invalid Boolean attribute length", IGRAPH_EINVAL);+                }+                IGRAPH_CHECK(igraph_vector_bool_append(oldbool, newbool));+                break;+            default:+                IGRAPH_WARNING("Invalid attribute type");+                break;+            }+        } 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;+            igraph_vector_bool_t *oldbool = (igraph_vector_bool_t *)oldrec->value;+            switch (oldrec->type) {+            case IGRAPH_ATTRIBUTE_NUMERIC:+                IGRAPH_CHECK(igraph_vector_resize(oldnum, origlen + ne));+                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;+            case IGRAPH_ATTRIBUTE_BOOLEAN:+                IGRAPH_CHECK(igraph_vector_bool_resize(oldbool, origlen + ne));+                for (j = origlen; j < origlen + ne; j++) {+                    VECTOR(*oldbool)[j] = 0;+                }+                break;+            default:+                IGRAPH_WARNING("Invalid attribute type");+                break;+            }+        }+    }++    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;+            igraph_vector_bool_t *oldbool, *newbool;+            switch (type) {+            case IGRAPH_ATTRIBUTE_NUMERIC:+                num = (igraph_vector_t*) oldrec->value;+                newnum = igraph_Calloc(1, igraph_vector_t);+                if (!newnum) {+                    IGRAPH_ERROR("Cannot permute edge 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_BOOLEAN:+                oldbool = (igraph_vector_bool_t*) oldrec->value;+                newbool = igraph_Calloc(1, igraph_vector_bool_t);+                if (!newbool) {+                    IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);+                }+                IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));+                IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);+                igraph_vector_bool_index(oldbool, newbool, idx);+                oldrec->value = newbool;+                igraph_vector_bool_destroy(oldbool);+                igraph_Free(oldbool);+                IGRAPH_FINALLY_CLEAN(1);+                break;+            case IGRAPH_ATTRIBUTE_STRING:+                str = (igraph_strvector_t*)oldrec->value;+                newstr = igraph_Calloc(1, igraph_strvector_t);+                if (!newstr) {+                    IGRAPH_ERROR("Cannot permute edge 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;+            igraph_vector_bool_t *oldbool, *newbool;++            /* 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 edge 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 edge 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;+            case IGRAPH_ATTRIBUTE_BOOLEAN:+                oldbool = (igraph_vector_bool_t*) oldrec->value;+                newbool = igraph_Calloc(1, igraph_vector_bool_t);+                if (!newbool) {+                    IGRAPH_ERROR("Cannot permute edge attributes", IGRAPH_ENOMEM);+                }+                IGRAPH_CHECK(igraph_vector_bool_init(newbool, 0));+                IGRAPH_FINALLY(igraph_vector_bool_destroy, newbool);+                igraph_vector_bool_index(oldbool, newbool, idx);+                new_rec->value = newbool;+                IGRAPH_FINALLY_CLEAN(1);+                break;+            default:+                IGRAPH_WARNING("Unknown edge attribute ignored");+            }+        }+        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;+    igraph_function_pointer_t *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, igraph_function_pointer_t);+    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;+        igraph_function_pointer_t 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];+        igraph_cattributes_combine_bool_t *boolfunc =+            (igraph_cattributes_combine_bool_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_BOOLEAN) {+            switch (todo) {+            case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:+                IGRAPH_CHECK(igraph_i_cattributes_cb_func(oldrec, newrec, merges,+                             boolfunc));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_SUM:+            case IGRAPH_ATTRIBUTE_COMBINE_MAX:+                IGRAPH_CHECK(igraph_i_cattributes_cb_any_is_true(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_PROD:+            case IGRAPH_ATTRIBUTE_COMBINE_MIN:+                IGRAPH_CHECK(igraph_i_cattributes_cb_all_is_true(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_MEAN:+            case IGRAPH_ATTRIBUTE_COMBINE_MEDIAN:+                IGRAPH_CHECK(igraph_i_cattributes_cb_majority(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_RANDOM:+                IGRAPH_CHECK(igraph_i_cattributes_cb_random(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_FIRST:+                IGRAPH_CHECK(igraph_i_cattributes_cb_first(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_LAST:+                IGRAPH_CHECK(igraph_i_cattributes_cb_last(oldrec, newrec, merges));+                break;+            case IGRAPH_ATTRIBUTE_COMBINE_CONCAT:+                IGRAPH_ERROR("Cannot calculate concatenation of Booleans",+                             IGRAPH_EATTRCOMBINE);+                break;+            default:+                IGRAPH_ERROR("Unknown attribute_combination",+                             IGRAPH_UNIMPLEMENTED);+                break;+            }+        } else if (type == IGRAPH_ATTRIBUTE_STRING) {+            switch (todo) {+            case IGRAPH_ATTRIBUTE_COMBINE_FUNCTION:+                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;+    igraph_vit_t it;+    long int i, j, v;+    igraph_attribute_record_t *rec;+    igraph_vector_bool_t *log;+    igraph_bool_t l = igraph_i_cattribute_find(val, name, &j);++    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_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 (i = 0; !IGRAPH_VIT_END(it); IGRAPH_VIT_NEXT(it), i++) {+            v = IGRAPH_VIT_GET(it);+            VECTOR(*value)[i] = VECTOR(*log)[v];+        }+        igraph_vit_destroy(&it);+        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(&amp;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);+    } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {+        igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value;+        igraph_vector_bool_destroy(boolvec);+    }+    igraph_Free(rec->name);+    igraph_Free(rec->value);+    igraph_Free(rec);+}++/**+ * \function igraph_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);+    }+}
+ igraph/src/centrality.c view
@@ -0,0 +1,3516 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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_int_t *edges;+    long int i, j, nlen;++    for (i = 0; i < n; i++) {+        edges = igraph_inclist_get(inclist, i);+        nlen = igraph_vector_int_size(edges);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*edges)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            to[i] += w * from[nei];+        }+    }++    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_int_t *neis;+    long int i, j, nlen;++    for (i = 0; i < n; i++) {+        neis = igraph_inclist_get(in, i);+        nlen = igraph_vector_int_size(neis);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int nei_edge = (long int) VECTOR(*neis)[j];+            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_int_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_int_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_int_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_real_t minweight;+    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;+    int cmp_result;+    const double eps = IGRAPH_SHORTEST_PATH_EPSILON;++    IGRAPH_UNUSED(nobigint);++    if (igraph_vector_size(weights) != no_of_edges) {+        IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);+    }+    minweight = igraph_vector_min(weights);+    if (minweight <= 0) {+        IGRAPH_ERROR("Weight vector must be positive", IGRAPH_EINVAL);+    } else if (minweight <= eps) {+        IGRAPH_WARNING("Some weights are smaller than epsilon, calculations may suffer from numerical precision.");+    }++    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, -1.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_int_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_int_size(neis);+            for (j = 0; j < nlen; j++) {+                long int edge = (long int) VECTOR(*neis)[j];+                long int to = IGRAPH_OTHER(graph, edge, minnei);+                igraph_real_t altdist = mindist + VECTOR(*weights)[edge];+                igraph_real_t curdist = VECTOR(dist)[to];++                if (curdist == 0) {+                    /* this means curdist is infinity */+                    cmp_result = -1;+                } else {+                    cmp_result = igraph_cmp_epsilon(altdist, curdist, eps);+                }++                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;+                    IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, to, -altdist));+                } else if (cmp_result < 0) {+                    /* 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;+                    IGRAPH_CHECK(igraph_2wheap_modify(&Q, to, -altdist));+                } else if (cmp_result == 0) {+                    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_real_t minweight;+    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;+    int cmp_result;+    const double eps = IGRAPH_SHORTEST_PATH_EPSILON;+    igraph_stack_t S;++    if (igraph_vector_size(weights) != no_of_edges) {+        IGRAPH_ERROR("Weight vector length does not match", IGRAPH_EINVAL);+    }+    minweight = igraph_vector_min(weights);+    if (minweight <= 0) {+        IGRAPH_ERROR("Weight vector must be positive", IGRAPH_EINVAL);+    } else if (minweight <= eps) {+        IGRAPH_WARNING("Some weights are smaller than epsilon, calculations may suffer from numerical precision.");+    }++    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, -1.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_int_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_int_size(neis);+            for (j = 0; j < nlen; j++) {+                long int edge = (long int) VECTOR(*neis)[j];+                long int to = IGRAPH_OTHER(graph, edge, minnei);+                igraph_real_t altdist = mindist + VECTOR(*weights)[edge];+                igraph_real_t curdist = VECTOR(distance)[to];++                if (curdist == 0) {+                    /* this means curdist is infinity */+                    cmp_result = -1;+                } else {+                    cmp_result = igraph_cmp_epsilon(altdist, curdist, eps);+                }++                /* printf("to=%ld, altdist = %lg, curdist = %lg, cmp = %d\n",+                  to, altdist, curdist-1, cmp_result); */+                if (curdist == 0) {+                    /* This is the first finite distance to 'to' */+                    igraph_vector_int_t *v = igraph_inclist_get(&fathers, to);+                    /* printf("Found first path to %li (from %li)\n", to, minnei); */+                    igraph_vector_int_resize(v, 1);+                    VECTOR(*v)[0] = edge;+                    VECTOR(nrgeo)[to] = VECTOR(nrgeo)[minnei];+                    VECTOR(distance)[to] = altdist;+                    IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, to, -altdist));+                } else if (cmp_result < 0) {+                    /* This is a shorter path */+                    igraph_vector_int_t *v = igraph_inclist_get(&fathers, to);+                    /* printf("Found a shorter path to %li (from %li)\n", to, minnei); */+                    igraph_vector_int_resize(v, 1);+                    VECTOR(*v)[0] = edge;+                    VECTOR(nrgeo)[to] = VECTOR(nrgeo)[minnei];+                    VECTOR(distance)[to] = altdist;+                    IGRAPH_CHECK(igraph_2wheap_modify(&Q, to, -altdist));+                } else if (cmp_result == 0) {+                    igraph_vector_int_t *v = igraph_inclist_get(&fathers, to);+                    /* printf("Found a second SP to %li (from %li)\n", to, minnei); */+                    igraph_vector_int_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_int_t *fatv = igraph_inclist_get(&fathers, w);+            long int fatv_len = igraph_vector_int_size(fatv);+            /* printf("Popping %li.\n", w); */+            for (j = 0; j < fatv_len; j++) {+                long int fedge = (long int) VECTOR(*fatv)[j];+                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_int_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_int_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);++            if (cutoff > 0 && distance[actnode] >= cutoff ) {+                continue;+            }++            /* check the neighbors and add to them to the queue if unseen before */+            neip = igraph_inclist_get(elist_out_p, actnode);+            neino = igraph_vector_int_size(neip);+            for (i = 0; i < neino; i++) {+                igraph_integer_t edge = (igraph_integer_t) VECTOR(*neip)[i], from, to;+                long int neighbor;+                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_int_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 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 longer than the longest possible geodesic in case+ * of unweighted graphs, but may not be so in weighted graphs, so it is+ * best not to use this function on weighted graphs.+ *+ * </para><para>+ * If the graph has a single vertex only, the closeness centrality of+ * that single vertex will be NaN (because we are essentially dividing+ * zero with zero).+ *+ * \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. */++    igraph_real_t minweight;+    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;++    int cmp_result;+    const double eps = IGRAPH_SHORTEST_PATH_EPSILON;+    igraph_real_t mindist;++    igraph_bool_t warning_shown = 0;++    if (igraph_vector_size(weights) != no_of_edges) {+        IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+    }++    minweight = igraph_vector_min(weights);+    if (minweight <= 0) {+        IGRAPH_ERROR("Weight vector must be positive", IGRAPH_EINVAL);+    } else if (minweight <= eps) {+        IGRAPH_WARNING("Some weights are smaller than epsilon, calculations may suffer from numerical precision.");+    }++    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, -1.0);+        VECTOR(which)[source] = i + 1;+        VECTOR(dist)[source] = 1.0;     /* actual distance is zero but we need to store distance + 1 */+        nodes_reached = 0;++        while (!igraph_2wheap_empty(&Q)) {+            igraph_integer_t minnei = (igraph_integer_t) igraph_2wheap_max_index(&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);++            mindist = -igraph_2wheap_delete_max(&Q);++            VECTOR(*res)[i] += (mindist - 1.0);+            nodes_reached++;++            if (cutoff > 0 && mindist >= cutoff + 1.0) {+                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 (curdist == 0) {+                    /* this means curdist is infinity */+                    cmp_result = -1;+                } else {+                    cmp_result = igraph_cmp_epsilon(altdist, curdist, eps);+                }++                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 (cmp_result < 0) {+                    /* 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];++        if (((cutoff > 0 && mindist < cutoff + 1.0) || (cutoff <= 0)) &&+            nodes_reached < no_of_nodes && !warning_shown) {+            IGRAPH_WARNING("closeness centrality is not well-defined for disconnected graphs");+            warning_shown = 1;+        }+    } /* !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 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;+    long int actdist;+    igraph_adjlist_t allneis;++    igraph_dqueue_t q;++    long int nodes_to_calc;+    igraph_vit_t vit;++    igraph_bool_t warning_shown = 0;++    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);+            actdist = (long int) igraph_dqueue_pop(&q);++            VECTOR(*res)[i] += actdist;++            if (cutoff > 0 && actdist >= cutoff) {+                continue;    /* NOT break!!! */+            }++            /* check the neighbors */+            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 (((cutoff > 0 && actdist < cutoff) || cutoff <= 0) &&+            no_of_nodes > nodes_reached && !warning_shown) {+            IGRAPH_WARNING("closeness centrality is not well-defined for disconnected graphs");+            warning_shown = 1;+        }+    }++    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;+}
+ igraph/src/cliquer.c view
@@ -0,0 +1,1778 @@++/*+ * This file contains the clique searching routines.+ *+ * Copyright (C) 2002 Sampo Niskanen, Patric Östergård.+ * Licensed under the GNU GPL, read the file LICENSE for details.+ */++#include <stdio.h>+#include <stdlib.h>+#include <limits.h>+/*+#include <unistd.h>+#include <sys/time.h>+#include <sys/times.h>+*/++#include "cliquer.h"++#include "config.h"++#ifdef USING_R+#include <R.h>+#endif++/* Default cliquer options */+IGRAPH_THREAD_LOCAL clique_options clique_default_options = {+    reorder_by_default, NULL, /*clique_print_time*/ NULL, NULL, NULL, NULL, NULL, 0+};+++/* Calculate d/q, rounding result upwards/downwards. */+#define DIV_UP(d,q) (((d)+(q)-1)/(q))+#define DIV_DOWN(d,q) ((int)((d)/(q)))+++/* Global variables used: */+/* These must be saved and restored in re-entrance. */+static IGRAPH_THREAD_LOCAL int *clique_size;      /* c[i] == max. clique size in {0,1,...,i-1} */+static IGRAPH_THREAD_LOCAL set_t current_clique;  /* Current clique being searched. */+static IGRAPH_THREAD_LOCAL set_t best_clique;     /* Largest/heaviest clique found so far. */+/*static struct tms cputimer;*/      /* Timer for opts->time_function() */+/*static struct timeval realtimer;*/ /* Timer for opts->time_function() */+static IGRAPH_THREAD_LOCAL int clique_list_count=0;  /* No. of cliques in opts->clique_list[] */+static IGRAPH_THREAD_LOCAL int weight_multiplier=1;  /* Weights multiplied by this when passing+				  * to time_function(). */++/* List cache (contains memory blocks of size g->n * sizeof(int)) */+static IGRAPH_THREAD_LOCAL int **temp_list=NULL;+static IGRAPH_THREAD_LOCAL int temp_count=0;+++/*+ * Macros for re-entrance.  ENTRANCE_SAVE() must be called immediately+ * after variable definitions, ENTRANCE_RESTORE() restores global+ * variables to original values.  entrance_level should be increased+ * and decreased accordingly.+ */+static IGRAPH_THREAD_LOCAL int entrance_level=0;  /* How many levels for entrance have occurred? */++#define ENTRANCE_SAVE() \+int *old_clique_size = clique_size;                     \+set_t old_current_clique = current_clique;              \+set_t old_best_clique = best_clique;                    \+int old_clique_list_count = clique_list_count;          \+int old_weight_multiplier = weight_multiplier;          \+int **old_temp_list = temp_list;                        \+int old_temp_count = temp_count;                        \+/*struct tms old_cputimer;                                \+struct timeval old_realtimer;                           \+memcpy(&old_cputimer,&cputimer,sizeof(struct tms));       \+memcpy(&old_realtimer,&realtimer,sizeof(struct timeval));*/++#define ENTRANCE_RESTORE() \+clique_size = old_clique_size;                          \+current_clique = old_current_clique;                    \+best_clique = old_best_clique;                          \+clique_list_count = old_clique_list_count;              \+weight_multiplier = old_weight_multiplier;              \+temp_list = old_temp_list;                              \+temp_count = old_temp_count;                            \+/*memcpy(&cputimer,&old_cputimer,sizeof(struct tms));       \+memcpy(&realtimer,&old_realtimer,sizeof(struct timeval));*/+++/* Number of clock ticks per second (as returned by sysconf(_SC_CLK_TCK)) */+/*static int clocks_per_sec=0;*/+++++/* Recursion and helper functions */+static boolean sub_unweighted_single(int *table, int size, int min_size,+				     graph_t *g);+static int sub_unweighted_all(int *table, int size, int min_size, int max_size,+			      boolean maximal, graph_t *g,+			      clique_options *opts);+static int sub_weighted_all(int *table, int size, int weight,+			    int current_weight, int prune_low, int prune_high,+			    int min_weight, int max_weight, boolean maximal,+			    graph_t *g, clique_options *opts);+++static boolean store_clique(set_t clique, graph_t *g, clique_options *opts);+static boolean is_maximal(set_t clique, graph_t *g);+static boolean false_function(set_t clique,graph_t *g,clique_options *opts);++++++/*****  Unweighted searches  *****/+/*+ * Unweighted searches are done separately from weighted searches because+ * some effective pruning methods can be used when the vertex weights+ * are all 1.  Single and all clique finding routines are separated,+ * because the single clique finding routine can store the found clique+ * while it is returning from the recursion, thus requiring no implicit+ * storing of the current clique.  When searching for all cliques the+ * current clique must be stored.+ */+++/*+ * unweighted_clique_search_single()+ *+ * Searches for a single clique of size min_size.  Stores maximum clique+ * sizes into clique_size[].+ *+ *   table    - the order of the vertices in g to use+ *   min_size - minimum size of clique to search for.  If min_size==0,+ *              searches for a maximum clique.+ *   g        - the graph+ *   opts     - time printing options+ *+ * opts->time_function is called after each base-level recursion, if+ * non-NULL.+ *+ * Returns the size of the clique found, or 0 if min_size>0 and a clique+ * of that size was not found (or if time_function aborted the search).+ * The largest clique found is stored in current_clique.+ *+ * Note: Does NOT use opts->user_function of opts->clique_list.+ */+static int unweighted_clique_search_single(int *table, int min_size,+					   graph_t *g, clique_options *opts) {+    /*+    struct tms tms;+	struct timeval timeval;+    */+	int i,j;+	int v,w;+	int *newtable;+	int newsize;++	v=table[0];+	clique_size[v]=1;+	set_empty(current_clique);+	SET_ADD_ELEMENT(current_clique,v);+	if (min_size==1)+		return 1;++	if (temp_count) {+		temp_count--;+		newtable=temp_list[temp_count];+	} else {+		newtable=malloc(g->n * sizeof(int));+	}+	for (i=1; i < g->n; i++) {+		w=v;+		v=table[i];++		newsize=0;+		for (j=0; j<i; j++) {+			if (GRAPH_IS_EDGE(g, v, table[j])) {+				newtable[newsize]=table[j];+				newsize++;+			}+		}++		if (sub_unweighted_single(newtable,newsize,clique_size[w],g)) {+			SET_ADD_ELEMENT(current_clique,v);+			clique_size[v]=clique_size[w]+1;+		} else {+			clique_size[v]=clique_size[w];+		}++        /*+		if (opts && opts->time_function) {+			gettimeofday(&timeval,NULL);+			times(&tms);+			if (!opts->time_function(entrance_level,+						 i+1,g->n,clique_size[v] *+						 weight_multiplier,+						 (double)(tms.tms_utime-+							  cputimer.tms_utime)/+						 clocks_per_sec,+						 timeval.tv_sec-+						 realtimer.tv_sec++						 (double)(timeval.tv_usec-+							  realtimer.tv_usec)/+						 1000000,opts)) {+				temp_list[temp_count++]=newtable;+				return 0;+			}+		}+        */++		if (min_size) {+			if (clique_size[v]>=min_size) {+				temp_list[temp_count++]=newtable;+				return clique_size[v];+			}+			if (clique_size[v]+g->n-i-1 < min_size) {+				temp_list[temp_count++]=newtable;+				return 0;+			}+		}+	}++	temp_list[temp_count++]=newtable;++	if (min_size)+		return 0;+	return clique_size[v];+}++/*+ * sub_unweighted_single()+ *+ * Recursion function for searching for a single clique of size min_size.+ *+ *    table    - subset of the vertices in graph+ *    size     - size of table+ *    min_size - size of clique to look for within the subgraph+ *               (decreased with every recursion)+ *    g        - the graph+ *+ * Returns TRUE if a clique of size min_size is found, FALSE otherwise.+ * If a clique of size min_size is found, it is stored in current_clique.+ *+ * clique_size[] for all values in table must be defined and correct,+ * otherwise inaccurate results may occur.+ */+static boolean sub_unweighted_single(int *table, int size, int min_size,+				     graph_t *g) {+	int i;+	int v;+	int *newtable;+	int *p1, *p2;++	/* Zero or one vertices needed anymore. */+	if (min_size <= 1) {+		if (size>0 && min_size==1) {+			set_empty(current_clique);+			SET_ADD_ELEMENT(current_clique,table[0]);+			return TRUE;+		}+		if (min_size==0) {+			set_empty(current_clique);+			return TRUE;+		}+		return FALSE;+	}+	if (size < min_size)+		return FALSE;++	/* Dynamic memory allocation with cache */+	if (temp_count) {+		temp_count--;+		newtable=temp_list[temp_count];+	} else {+		newtable=malloc(g->n * sizeof(int));+	}++	for (i = size-1; i >= 0; i--) {+		v = table[i];++		if (clique_size[v] < min_size)+			break;+		/* This is faster when compiling with gcc than placing+		 * this in the for-loop condition. */+		if (i+1 < min_size)+			break;++		/* Very ugly code, but works faster than "for (i=...)" */+		p1 = newtable;+		for (p2=table; p2 < table+i; p2++) {+			int w = *p2;+			if (GRAPH_IS_EDGE(g, v, w)) {+				*p1 = w;+				p1++;+			}+		}++		/* Avoid unneccessary loops (next size == p1-newtable) */+		if (p1-newtable < min_size-1)+			continue;+		/* Now p1-newtable >= min_size-1 >= 2-1 == 1, so we can use+		 * p1-newtable-1 safely. */+		if (clique_size[newtable[p1-newtable-1]] < min_size-1)+			continue;++		if (sub_unweighted_single(newtable,p1-newtable,+					  min_size-1,g)) {+			/* Clique found. */+			SET_ADD_ELEMENT(current_clique,v);+			temp_list[temp_count++]=newtable;+			return TRUE;+		}+	}+	temp_list[temp_count++]=newtable;+	return FALSE;+}+++/*+ * unweighted_clique_search_all()+ *+ * Searches for all cliques with size at least min_size and at most+ * max_size.  Stores the cliques as opts declares.+ *+ *   table    - the order of the vertices in g to search+ *   start    - first index where the subgraph table[0], ..., table[start]+ *              might include a requested kind of clique+ *   min_size - minimum size of clique to search for.  min_size > 0 !+ *   max_size - maximum size of clique to search for.  If no upper limit+ *              is desired, use eg. INT_MAX+ *   maximal  - requires cliques to be maximal+ *   g        - the graph+ *   opts     - time printing and clique storage options+ *+ * Cliques found are stored as defined by opts->user_function and+ * opts->clique_list.  opts->time_function is called after each+ * base-level recursion, if non-NULL.+ *+ * clique_size[] must be defined and correct for all values of+ * table[0], ..., table[start-1].+ *+ * Returns the number of cliques stored (not neccessarily number of cliques+ * in graph, if user/time_function aborts).+ */+static int unweighted_clique_search_all(int *table, int start,+					int min_size, int max_size,+					boolean maximal, graph_t *g,+					clique_options *opts) {+    /*+	struct timeval timeval;+	struct tms tms;+    */+	int i,j;+	int v;+	int *newtable;+	int newsize;+	int count=0;++	if (temp_count) {+		temp_count--;+		newtable=temp_list[temp_count];+	} else {+		newtable=malloc(g->n * sizeof(int));+	}++	clique_list_count=0;+	set_empty(current_clique);+	for (i=start; i < g->n; i++) {+		v=table[i];+		clique_size[v]=min_size;  /* Do not prune here. */++		newsize=0;+		for (j=0; j<i; j++) {+			if (GRAPH_IS_EDGE(g,v,table[j])) {+				newtable[newsize]=table[j];+				newsize++;+			}+		}++		SET_ADD_ELEMENT(current_clique,v);+		j=sub_unweighted_all(newtable,newsize,min_size-1,max_size-1,+				     maximal,g,opts);+		SET_DEL_ELEMENT(current_clique,v);+		if (j<0) {+			/* Abort. */+			count-=j;+			break;+		}+		count+=j;++#if 0+		if (opts->time_function) {+			gettimeofday(&timeval,NULL);+			times(&tms);+			if (!opts->time_function(entrance_level,+						 i+1,g->n,min_size *+						 weight_multiplier,+						 (double)(tms.tms_utime-+							  cputimer.tms_utime)/+						 clocks_per_sec,+						 timeval.tv_sec-+						 realtimer.tv_sec++						 (double)(timeval.tv_usec-+							  realtimer.tv_usec)/+						 1000000,opts)) {+				/* Abort. */+				break;+			}+		}+#endif+	}+	temp_list[temp_count++]=newtable;+	return count;+}++/*+ * sub_unweighted_all()+ *+ * Recursion function for searching for all cliques of given size.+ *+ *   table    - subset of vertices of graph g+ *   size     - size of table+ *   min_size - minimum size of cliques to search for (decreased with+ *              every recursion)+ *   max_size - maximum size of cliques to search for (decreased with+ *              every recursion).  If no upper limit is desired, use+ *              eg. INT_MAX+ *   maximal  - require cliques to be maximal (passed through)+ *   g        - the graph+ *   opts     - storage options+ *+ * All cliques of suitable size found are stored according to opts.+ *+ * Returns the number of cliques found.  If user_function returns FALSE,+ * then the number of cliques is returned negative.+ *+ * Uses current_clique to store the currently-being-searched clique.+ * clique_size[] for all values in table must be defined and correct,+ * otherwise inaccurate results may occur.+ */+static int sub_unweighted_all(int *table, int size, int min_size, int max_size,+			      boolean maximal, graph_t *g,+			      clique_options *opts) {+	int i;+	int v;+	int n;+	int *newtable;+	int *p1, *p2;+	int count=0;     /* Amount of cliques found */++	if (min_size <= 0) {+		if ((!maximal) || is_maximal(current_clique,g)) {+			/* We've found one.  Store it. */+			count++;+			if (!store_clique(current_clique,g,opts)) {+				return -count;+			}+		}+		if (max_size <= 0) {+			/* If we add another element, size will be too big. */+			return count;+		}+	}++	if (size < min_size) {+		return count;+	}++	/* Dynamic memory allocation with cache */+	if (temp_count) {+		temp_count--;+		newtable=temp_list[temp_count];+	} else {+		newtable=malloc(g->n * sizeof(int));+	}++	for (i=size-1; i>=0; i--) {+		v = table[i];+		if (clique_size[v] < min_size) {+			break;+		}+		if (i+1 < min_size) {+			break;+		}++		/* Very ugly code, but works faster than "for (i=...)" */+		p1 = newtable;+		for (p2=table; p2 < table+i; p2++) {+			int w = *p2;+			if (GRAPH_IS_EDGE(g, v, w)) {+				*p1 = w;+				p1++;+			}+		}++		/* Avoid unneccessary loops (next size == p1-newtable) */+		if (p1-newtable < min_size-1) {+			continue;+		}++		SET_ADD_ELEMENT(current_clique,v);+		n=sub_unweighted_all(newtable,p1-newtable,+				     min_size-1,max_size-1,maximal,g,opts);+		SET_DEL_ELEMENT(current_clique,v);+		if (n < 0) {+			/* Abort. */+			count -= n;+			count = -count;+			break;+		}+		count+=n;+	}+	temp_list[temp_count++]=newtable;+	return count;+}+++++/***** Weighted clique searches *****/+/*+ * Weighted clique searches can use the same recursive routine, because+ * in both cases (single/all) they have to search through all potential+ * permutations searching for heavier cliques.+ */+++/*+ * weighted_clique_search_single()+ *+ * Searches for a single clique of weight at least min_weight, and at+ * most max_weight.  Stores maximum clique sizes into clique_size[]+ * (or min_weight-1, whichever is smaller).+ *+ *   table      - the order of the vertices in g to use+ *   min_weight - minimum weight of clique to search for.  If min_weight==0,+ *                then searches for a maximum weight clique+ *   max_weight - maximum weight of clique to search for.  If no upper limit+ *                is desired, use eg. INT_MAX+ *   g          - the graph+ *   opts       - time printing options+ *+ * opts->time_function is called after each base-level recursion, if+ * non-NULL.+ *+ * Returns 0 if a clique of requested weight was not found (also if+ * time_function requested an abort), otherwise returns >= 1.+ * If min_weight==0 (search for maximum-weight clique), then the return+ * value is the weight of the clique found.  The found clique is stored+ * in best_clique.+ *+ * Note: Does NOT use opts->user_function of opts->clique_list.+ */+static int weighted_clique_search_single(int *table, int min_weight,+					 int max_weight, graph_t *g,+					 clique_options *opts) {+    /*+	struct timeval timeval;+	struct tms tms;+    */+	int i,j;+	int v;+	int *newtable;+	int newsize;+	int newweight;+	int search_weight;+	int min_w;+	clique_options localopts;++	if (min_weight==0)+		min_w=INT_MAX;+	else+		min_w=min_weight;+++	if (min_weight==1) {+		/* min_weight==1 may cause trouble in the routine, and+		 * it's trivial to check as it's own case.+		 * We write nothing to clique_size[]. */+		for (i=0; i < g->n; i++) {+			if (g->weights[table[i]] <= max_weight) {+				set_empty(best_clique);+				SET_ADD_ELEMENT(best_clique,table[i]);+				return g->weights[table[i]];+			}+		}+		return 0;+	}+	+	localopts.time_function=NULL;+	localopts.reorder_function=NULL;+	localopts.reorder_map=NULL;+	localopts.user_function=false_function;+	localopts.user_data=NULL;+	localopts.clique_list=&best_clique;+	localopts.clique_list_length=1;+	clique_list_count=0;++	v=table[0];+	set_empty(best_clique);+	SET_ADD_ELEMENT(best_clique,v);+	search_weight=g->weights[v];+	if (min_weight && (search_weight >= min_weight)) {+		if (search_weight <= max_weight) {+			/* Found suitable clique. */+			return search_weight;+		}+		search_weight=min_weight-1;+	}+	clique_size[v]=search_weight;+	set_empty(current_clique);++	if (temp_count) {+		temp_count--;+		newtable=temp_list[temp_count];+	} else {+		newtable=malloc(g->n * sizeof(int));+	}++	for (i = 1; i < g->n; i++) {+		v=table[i];++		newsize=0;+		newweight=0;+		for (j=0; j<i; j++) {+			if (GRAPH_IS_EDGE(g,v,table[j])) {+				newweight += g->weights[table[j]];+				newtable[newsize]=table[j];+				newsize++;+			}+		}+++		SET_ADD_ELEMENT(current_clique,v);+		search_weight=sub_weighted_all(newtable,newsize,newweight,+					       g->weights[v],search_weight,+					       clique_size[table[i-1]] ++					       g->weights[v],+					       min_w,max_weight,FALSE,+					       g,&localopts);+		SET_DEL_ELEMENT(current_clique,v);+		if (search_weight < 0) {+			break;+		}++		clique_size[v]=search_weight;++        /*+		if (opts->time_function) {+			gettimeofday(&timeval,NULL);+			times(&tms);+			if (!opts->time_function(entrance_level,+						 i+1,g->n,clique_size[v] *+						 weight_multiplier,+						 (double)(tms.tms_utime-+							  cputimer.tms_utime)/+						 clocks_per_sec,+						 timeval.tv_sec-+						 realtimer.tv_sec++						 (double)(timeval.tv_usec-+							  realtimer.tv_usec)/+						 1000000,opts)) {+				set_free(current_clique);+				current_clique=NULL;+				break;+			}+		}+        */+	}+	temp_list[temp_count++]=newtable;+	if (min_weight && (search_weight > 0)) {+		/* Requested clique has not been found. */+		return 0;+	}+	return clique_size[table[i-1]];+}+++/*+ * weighted_clique_search_all()+ *+ * Searches for all cliques with weight at least min_weight and at most+ * max_weight.  Stores the cliques as opts declares.+ *+ *   table      - the order of the vertices in g to search+ *   start      - first index where the subgraph table[0], ..., table[start]+ *                might include a requested kind of clique+ *   min_weight - minimum weight of clique to search for.  min_weight > 0 !+ *   max_weight - maximum weight of clique to search for.  If no upper limit+ *                is desired, use eg. INT_MAX+ *   maximal    - search only for maximal cliques+ *   g          - the graph+ *   opts       - time printing and clique storage options+ *+ * Cliques found are stored as defined by opts->user_function and+ * opts->clique_list.  opts->time_function is called after each+ * base-level recursion, if non-NULL.+ *+ * clique_size[] must be defined and correct for all values of+ * table[0], ..., table[start-1].+ *+ * Returns the number of cliques stored (not neccessarily number of cliques+ * in graph, if user/time_function aborts).+ */+static int weighted_clique_search_all(int *table, int start,+				      int min_weight, int max_weight,+				      boolean maximal, graph_t *g,+				      clique_options *opts) {+    /*+	struct timeval timeval;+	struct tms tms;+    */+	int i,j;+	int v;+	int *newtable;+	int newsize;+	int newweight;++	if (temp_count) {+		temp_count--;+		newtable=temp_list[temp_count];+	} else {+		newtable=malloc(g->n * sizeof(int));+	}++	clique_list_count=0;+	set_empty(current_clique);+	for (i=start; i < g->n; i++) {+		v=table[i];+		clique_size[v]=min_weight;   /* Do not prune here. */++		newsize=0;+		newweight=0;+		for (j=0; j<i; j++) {+			if (GRAPH_IS_EDGE(g,v,table[j])) {+				newtable[newsize]=table[j];+				newweight+=g->weights[table[j]];+				newsize++;+			}+		}++		SET_ADD_ELEMENT(current_clique,v);+		j=sub_weighted_all(newtable,newsize,newweight,+				   g->weights[v],min_weight-1,INT_MAX,+				   min_weight,max_weight,maximal,g,opts);+		SET_DEL_ELEMENT(current_clique,v);++		if (j<0) {+			/* Abort. */+			break;+		}++        /*+		if (opts->time_function) {+			gettimeofday(&timeval,NULL);+			times(&tms);+			if (!opts->time_function(entrance_level,+						 i+1,g->n,clique_size[v] *+						 weight_multiplier,+						 (double)(tms.tms_utime-+							  cputimer.tms_utime)/+						 clocks_per_sec,+						 timeval.tv_sec-+						 realtimer.tv_sec++						 (double)(timeval.tv_usec-+							  realtimer.tv_usec)/+						 1000000,opts)) {+				set_free(current_clique);+				current_clique=NULL;+				break;+			}+		}+        */+	}+	temp_list[temp_count++]=newtable;++	return clique_list_count;+}++/*+ * sub_weighted_all()+ *+ * Recursion function for searching for all cliques of given weight.+ *+ *   table      - subset of vertices of graph g+ *   size       - size of table+ *   weight     - total weight of vertices in table+ *   current_weight - weight of clique found so far+ *   prune_low  - ignore all cliques with weight less or equal to this value+ *                (often heaviest clique found so far)  (passed through)+ *   prune_high - maximum weight possible for clique in this subgraph+ *                (passed through)+ *   min_size   - minimum weight of cliques to search for (passed through)+ *                Must be greater than 0.+ *   max_size   - maximum weight of cliques to search for (passed through)+ *                If no upper limit is desired, use eg. INT_MAX+ *   maximal    - search only for maximal cliques+ *   g          - the graph+ *   opts       - storage options+ *+ * All cliques of suitable weight found are stored according to opts.+ *+ * Returns weight of heaviest clique found (prune_low if a heavier clique+ * hasn't been found);  if a clique with weight at least min_size is found+ * then min_size-1 is returned.  If clique storage failed, -1 is returned.+ *+ * The largest clique found smaller than max_weight is stored in+ * best_clique, if non-NULL.+ *+ * Uses current_clique to store the currently-being-searched clique.+ * clique_size[] for all values in table must be defined and correct,+ * otherwise inaccurate results may occur.+ *+ * To search for a single maximum clique, use min_weight==max_weight==INT_MAX,+ * with best_clique non-NULL.  To search for a single given-weight clique,+ * use opts->clique_list and opts->user_function=false_function.  When+ * searching for all cliques, min_weight should be given the minimum weight+ * desired.+ */+static int sub_weighted_all(int *table, int size, int weight,+			    int current_weight, int prune_low, int prune_high,+			    int min_weight, int max_weight, boolean maximal,+			    graph_t *g, clique_options *opts) {+	int i;+	int v,w;+	int *newtable;+	int *p1, *p2;+	int newweight;++	if (current_weight >= min_weight) {+		if ((current_weight <= max_weight) &&+		    ((!maximal) || is_maximal(current_clique,g))) {+			/* We've found one.  Store it. */+			if (!store_clique(current_clique,g,opts)) {+				return -1;+			}+		}+		if (current_weight >= max_weight) {+			/* Clique too heavy. */+			return min_weight-1;+		} +	}+	if (size <= 0) {+		/* current_weight < min_weight, prune_low < min_weight,+		 * so return value is always < min_weight. */+		if (current_weight>prune_low) {+			if (best_clique) {+				best_clique = set_copy(best_clique,current_clique);+			}+			if (current_weight < min_weight)+				return current_weight;+			else+				return min_weight-1;+		} else {+			return prune_low;+		}+	}++	/* Dynamic memory allocation with cache */+	if (temp_count) {+		temp_count--;+		newtable=temp_list[temp_count];+	} else {+		newtable=malloc(g->n * sizeof(int));+	}++	for (i = size-1; i >= 0; i--) {+		v = table[i];+		if (current_weight+clique_size[v] <= prune_low) {+			/* Dealing with subset without heavy enough clique. */+			break;+		}+		if (current_weight+weight <= prune_low) {+			/* Even if all elements are added, won't do. */+			break;+		}++		/* Very ugly code, but works faster than "for (i=...)" */+		p1 = newtable;+		newweight = 0;+		for (p2=table; p2 < table+i; p2++) {+			w = *p2;+			if (GRAPH_IS_EDGE(g, v, w)) {+				*p1 = w;+				newweight += g->weights[w];+				p1++;+			}+		}++		w=g->weights[v];+		weight-=w;+		/* Avoid a few unneccessary loops */+		if (current_weight+w+newweight <= prune_low) {+			continue;+		}++		SET_ADD_ELEMENT(current_clique,v);+		prune_low=sub_weighted_all(newtable,p1-newtable,+					   newweight,+					   current_weight+w,+					   prune_low,prune_high,+					   min_weight,max_weight,maximal,+					   g,opts);+		SET_DEL_ELEMENT(current_clique,v);+		if ((prune_low<0) || (prune_low>=prune_high)) {+			/* Impossible to find larger clique. */+			break;+		}+	}+	temp_list[temp_count++]=newtable;+	return prune_low;+}+++++/***** Helper functions *****/+++/*+ * store_clique()+ *+ * Stores a clique according to given user options.+ *+ *   clique - the clique to store+ *   opts   - storage options+ *+ * Returns FALSE if opts->user_function() returned FALSE; otherwise+ * returns TRUE.+ */+static boolean store_clique(set_t clique, graph_t *g, clique_options *opts) {++	clique_list_count++;++	/* clique_list[] */+	if (opts->clique_list) {+		/*+		 * This has been a major source of bugs:+		 * Has clique_list_count been set to 0 before calling+		 * the recursions? +		 */+		if (clique_list_count <= 0) {+#ifdef USING_R+		        error("CLIQUER INTERNAL ERROR: ",+			      "clique_list_count has negative value!");+#else+			fprintf(stderr,"CLIQUER INTERNAL ERROR: "+				"clique_list_count has negative value!\n");+			fprintf(stderr,"Please report as a bug.\n");+			abort();+#endif+		}+		if (clique_list_count <= opts->clique_list_length)+			opts->clique_list[clique_list_count-1] =+				set_copy(opts->clique_list[clique_list_count-1], clique);+	}++	/* user_function() */+	if (opts->user_function) {+		if (!opts->user_function(clique,g,opts)) {+			/* User function requested abort. */+			return FALSE;+		}+	}++	return TRUE;+}++/*+ * maximalize_clique()+ *+ * Adds greedily all possible vertices in g to set s to make it a maximal+ * clique.+ *+ *   s - clique of vertices to make maximal+ *   g - graph+ *+ * Note: Not very optimized (uses a simple O(n^2) routine), but is called+ *       at maximum once per clique_xxx() call, so it shouldn't matter.+ */+static void maximalize_clique(set_t s,graph_t *g) {+	int i,j;+	boolean add;++	for (i=0; i < g->n; i++) {+		add=TRUE;+		for (j=0; j < g->n; j++) {+			if (SET_CONTAINS_FAST(s,j) && !GRAPH_IS_EDGE(g,i,j)) {+				add=FALSE;+				break;+			}+		}+		if (add) {+			SET_ADD_ELEMENT(s,i);+		}+	}+	return;+}+++/*+ * is_maximal()+ *+ * Check whether a clique is maximal or not.+ *+ *   clique - set of vertices in clique+ *   g      - graph+ *+ * Returns TRUE is clique is a maximal clique of g, otherwise FALSE.+ */+static boolean is_maximal(set_t clique, graph_t *g) {+	int i,j;+	int *table;+	int len;+	boolean addable;++	if (temp_count) {+		temp_count--;+		table=temp_list[temp_count];+	} else {+		table=malloc(g->n * sizeof(int));+	}++	len=0;+	for (i=0; i < g->n; i++)+		if (SET_CONTAINS_FAST(clique,i))+			table[len++]=i;++	for (i=0; i < g->n; i++) {+		addable=TRUE;+		for (j=0; j<len; j++) {+			if (!GRAPH_IS_EDGE(g,i,table[j])) {+				addable=FALSE;+				break;+			}+		}+		if (addable) {+			temp_list[temp_count++]=table;+			return FALSE;+		}+	}+	temp_list[temp_count++]=table;+	return TRUE;+}+++/*+ * false_function()+ *+ * Returns FALSE.  Can be used as user_function.+ */+static boolean false_function(set_t clique,graph_t *g,clique_options *opts) {+	return FALSE;+}+++++/***** API-functions *****/++/*+ * clique_unweighted_max_weight()+ *+ * Returns the size of the maximum (sized) clique in g (or 0 if search+ * was aborted).+ *+ *   g    - the graph+ *   opts - time printing options+ *+ * Note: As we don't have an algorithm faster than actually finding+ *       a maximum clique, we use clique_unweighted_find_single().+ *       This incurs only very small overhead.+ */+int clique_unweighted_max_weight(graph_t *g, clique_options *opts) {+	set_t s;+	int size;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(g!=NULL);++	s=clique_unweighted_find_single(g,0,0,FALSE,opts);+	if (s==NULL) {+		/* Search was aborted. */+		return 0;+	}+	size=set_size(s);+	set_free(s);+	return size;+}+++/*+ * clique_unweighted_find_single()+ *+ * Returns a clique with size at least min_size and at most max_size.+ *+ *   g        - the graph+ *   min_size - minimum size of clique to search for.  If min_size==0,+ *              searches for maximum clique.+ *   max_size - maximum size of clique to search for.  If max_size==0, no+ *              upper limit is used.  If min_size==0, this must also be 0.+ *   maximal  - require returned clique to be maximal+ *   opts     - time printing options+ *+ * Returns the set of vertices forming the clique, or NULL if a clique+ * of requested size/maximality does not exist in the graph  (or if+ * opts->time_function() requests abort).+ *+ * The returned clique is newly allocated and can be freed by set_free().+ *+ * Note: Does NOT use opts->user_function() or opts->clique_list[].+ */+set_t clique_unweighted_find_single(graph_t *g,int min_size,int max_size,+				    boolean maximal, clique_options *opts) {+	int i;+	int *table;+	set_t s;++	ENTRANCE_SAVE();+	entrance_level++;++	if (opts==NULL)+		opts=&clique_default_options;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(g!=NULL);+	ASSERT(min_size>=0);+	ASSERT(max_size>=0);+	ASSERT((max_size==0) || (min_size <= max_size));+	ASSERT(!((min_size==0) && (max_size>0)));+	ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL));++	if ((max_size>0) && (min_size>max_size)) {+		/* state was not changed */+		entrance_level--;+		return NULL;+	}++    /*+	if (clocks_per_sec==0)+		clocks_per_sec=sysconf(_SC_CLK_TCK);+	ASSERT(clocks_per_sec>0);+    */++	/* Dynamic allocation */+	current_clique=set_new(g->n);+	clique_size=malloc(g->n * sizeof(int));+	/* table allocated later */+	temp_list=malloc((g->n+2)*sizeof(int *));+	temp_count=0;++	/* "start clock" */+    /*+	gettimeofday(&realtimer,NULL);+	times(&cputimer);+    */++	/* reorder */+	if (opts->reorder_function) {+		table=opts->reorder_function(g,FALSE);+	} else if (opts->reorder_map) {+		table=reorder_duplicate(opts->reorder_map,g->n);+	} else {+		table=reorder_ident(g->n);+	}+	ASSERT(reorder_is_bijection(table,g->n));+++	if (unweighted_clique_search_single(table,min_size,g,opts)==0) {+		set_free(current_clique);+		current_clique=NULL;+		goto cleanreturn;+	}+	if (maximal && (min_size>0)) {+		maximalize_clique(current_clique,g);++		if ((max_size > 0) && (set_size(current_clique) > max_size)) {+			clique_options localopts;++			s = set_new(g->n);+			localopts.time_function = opts->time_function;+			localopts.output = opts->output;+			localopts.user_function = false_function;+			localopts.clique_list = &s;+			localopts.clique_list_length = 1;++			for (i=0; i < g->n-1; i++)+				if (clique_size[table[i]]>=min_size)+					break;+			if (unweighted_clique_search_all(table,i,min_size,+							 max_size,maximal,+							 g,&localopts)) {+				set_free(current_clique);+				current_clique=s;+			} else {+				set_free(current_clique);+				current_clique=NULL;+			}+		}+	}+	+    cleanreturn:+	s=current_clique;++	/* Free resources */+	for (i=0; i < temp_count; i++)+		free(temp_list[i]);+	free(temp_list);+	free(table);+	free(clique_size);++	ENTRANCE_RESTORE();+	entrance_level--;++	return s;+}+++/*+ * clique_unweighted_find_all()+ *+ * Find all cliques with size at least min_size and at most max_size.+ *+ *   g        - the graph+ *   min_size - minimum size of cliques to search for.  If min_size==0,+ *              searches for maximum cliques.+ *   max_size - maximum size of cliques to search for.  If max_size==0, no+ *              upper limit is used.  If min_size==0, this must also be 0.+ *   maximal  - require cliques to be maximal cliques+ *   opts     - time printing and clique storage options+ *+ * Returns the number of cliques found.  This can be less than the number+ * of cliques in the graph iff opts->time_function() or opts->user_function()+ * returns FALSE (request abort).+ *+ * The cliques found are stored in opts->clique_list[] and+ * opts->user_function() is called with them (if non-NULL).  The cliques+ * stored in opts->clique_list[] are newly allocated, and can be freed+ * by set_free().+ */+int clique_unweighted_find_all(graph_t *g, int min_size, int max_size,+			       boolean maximal, clique_options *opts) {+	int i;+	int *table;+	int count;++	ENTRANCE_SAVE();+	entrance_level++;++	if (opts==NULL)+		opts=&clique_default_options;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(g!=NULL);+	ASSERT(min_size>=0);+	ASSERT(max_size>=0);+	ASSERT((max_size==0) || (min_size <= max_size));+	ASSERT(!((min_size==0) && (max_size>0)));+	ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL));++	if ((max_size>0) && (min_size>max_size)) {+		/* state was not changed */+		entrance_level--;+		return 0;+	}++    /*+	if (clocks_per_sec==0)+		clocks_per_sec=sysconf(_SC_CLK_TCK);+	ASSERT(clocks_per_sec>0);+    */++	/* Dynamic allocation */+	current_clique=set_new(g->n);+	clique_size=malloc(g->n * sizeof(int));+	/* table allocated later */+	temp_list=malloc((g->n+2)*sizeof(int *));+	temp_count=0;++	clique_list_count=0;+	memset(clique_size,0,g->n * sizeof(int));++	/* "start clock" */+    /*+	gettimeofday(&realtimer,NULL);+	times(&cputimer);+    */++	/* reorder */+	if (opts->reorder_function) {+		table=opts->reorder_function(g,FALSE);+	} else if (opts->reorder_map) {+		table=reorder_duplicate(opts->reorder_map,g->n);+	} else {+		table=reorder_ident(g->n);+	}+	ASSERT(reorder_is_bijection(table,g->n));+++	/* Search as normal until there is a chance to find a suitable+	 * clique. */+	if (unweighted_clique_search_single(table,min_size,g,opts)==0) {+		count=0;+		goto cleanreturn;+	}++	if (min_size==0 && max_size==0) {+		min_size=max_size=clique_size[table[g->n-1]];+		maximal=FALSE;  /* No need to test, since we're searching+				 * for maximum cliques. */+	}+	if (max_size==0) {+		max_size=INT_MAX;+	}++	for (i=0; i < g->n-1; i++)+		if (clique_size[table[i]] >= min_size)+			break;+	count=unweighted_clique_search_all(table,i,min_size,max_size,+					   maximal,g,opts);++  cleanreturn:+	/* Free resources */+	for (i=0; i<temp_count; i++)+		free(temp_list[i]);+	free(temp_list);+	free(table);+	free(clique_size);+	set_free(current_clique);++	ENTRANCE_RESTORE();+	entrance_level--;++	return count;+}+++++/*+ * clique_max_weight()+ *+ * Returns the weight of the maximum weight clique in the graph (or 0 if+ * the search was aborted).+ *+ *   g    - the graph+ *   opts - time printing options+ *+ * Note: As we don't have an algorithm faster than actually finding+ *       a maximum weight clique, we use clique_find_single().+ *       This incurs only very small overhead.+ */+int clique_max_weight(graph_t *g,clique_options *opts) {+	set_t s;+	int weight;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(g!=NULL);++	s=clique_find_single(g,0,0,FALSE,opts);+	if (s==NULL) {+		/* Search was aborted. */+		return 0;+	}+	weight=graph_subgraph_weight(g,s);+	set_free(s);+	return weight;+}+++/*+ * clique_find_single()+ *+ * Returns a clique with weight at least min_weight and at most max_weight.+ *+ *   g          - the graph+ *   min_weight - minimum weight of clique to search for.  If min_weight==0,+ *                searches for a maximum weight clique.+ *   max_weight - maximum weight of clique to search for.  If max_weight==0,+ *                no upper limit is used.  If min_weight==0, max_weight must+ *                also be 0.+ *   maximal    - require returned clique to be maximal+ *   opts       - time printing options+ *+ * Returns the set of vertices forming the clique, or NULL if a clique+ * of requested weight/maximality does not exist in the graph  (or if+ * opts->time_function() requests abort).+ *+ * The returned clique is newly allocated and can be freed by set_free().+ *+ * Note: Does NOT use opts->user_function() or opts->clique_list[].+ * Note: Automatically uses clique_unweighted_find_single if all vertex+ *       weights are the same.+ */+set_t clique_find_single(graph_t *g,int min_weight,int max_weight,+			 boolean maximal, clique_options *opts) {+	int i;+	int *table;+	set_t s;++	ENTRANCE_SAVE();+	entrance_level++;++	if (opts==NULL)+		opts=&clique_default_options;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(g!=NULL);+	ASSERT(min_weight>=0);+	ASSERT(max_weight>=0);+	ASSERT((max_weight==0) || (min_weight <= max_weight));+	ASSERT(!((min_weight==0) && (max_weight>0)));+	ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL));++	if ((max_weight>0) && (min_weight>max_weight)) {+		/* state was not changed */+		entrance_level--;+		return NULL;+	}++    /*+	if (clocks_per_sec==0)+		clocks_per_sec=sysconf(_SC_CLK_TCK);+	ASSERT(clocks_per_sec>0);+    */++	/* Check whether we can use unweighted routines. */+	if (!graph_weighted(g)) {+		min_weight=DIV_UP(min_weight,g->weights[0]);+		if (max_weight) {+			max_weight=DIV_DOWN(max_weight,g->weights[0]);+			if (max_weight < min_weight) {+				/* state was not changed */+				entrance_level--;+				return NULL;+			}+		}++		weight_multiplier = g->weights[0];+		entrance_level--;+		s=clique_unweighted_find_single(g,min_weight,max_weight,+						maximal,opts);+		ENTRANCE_RESTORE();+		return s;+	}++	/* Dynamic allocation */+	current_clique=set_new(g->n);+	best_clique=set_new(g->n);+	clique_size=malloc(g->n * sizeof(int));+	memset(clique_size, 0, g->n * sizeof(int));+	/* table allocated later */+	temp_list=malloc((g->n+2)*sizeof(int *));+	temp_count=0;++	clique_list_count=0;++	/* "start clock" */+    /*+	gettimeofday(&realtimer,NULL);+	times(&cputimer);+    */++	/* reorder */+	if (opts->reorder_function) {+		table=opts->reorder_function(g,TRUE);+	} else if (opts->reorder_map) {+		table=reorder_duplicate(opts->reorder_map,g->n);+	} else {+		table=reorder_ident(g->n);+	}+	ASSERT(reorder_is_bijection(table,g->n));++	if (max_weight==0)+		max_weight=INT_MAX;++	if (weighted_clique_search_single(table,min_weight,max_weight,+					  g,opts)==0) {+		/* Requested clique has not been found. */+		set_free(best_clique);+		best_clique=NULL;+		goto cleanreturn;+	}+	if (maximal && (min_weight>0)) {+		maximalize_clique(best_clique,g);+		if (graph_subgraph_weight(g,best_clique) > max_weight) {+			clique_options localopts;++			localopts.time_function = opts->time_function;+			localopts.output = opts->output;+			localopts.user_function = false_function;+			localopts.clique_list = &best_clique;+			localopts.clique_list_length = 1;++			for (i=0; i < g->n-1; i++)+				if ((clique_size[table[i]] >= min_weight) ||+				    (clique_size[table[i]] == 0))+					break;+			if (!weighted_clique_search_all(table,i,min_weight,+							max_weight,maximal,+							g,&localopts)) {+				set_free(best_clique);+				best_clique=NULL;+			}+		}+	}++ cleanreturn:+	s=best_clique;++	/* Free resources */+	for (i=0; i < temp_count; i++)+		free(temp_list[i]);+	free(temp_list);+	temp_list=NULL;+	temp_count=0;+	free(table);+	set_free(current_clique);+	current_clique=NULL;+	free(clique_size);+	clique_size=NULL;++	ENTRANCE_RESTORE();+	entrance_level--;++	return s;+}++++++/*+ * clique_find_all()+ *+ * Find all cliques with weight at least min_weight and at most max_weight.+ *+ *   g          - the graph+ *   min_weight - minimum weight of cliques to search for.  If min_weight==0,+ *                searches for maximum weight cliques.+ *   max_weight - maximum weight of cliques to search for.  If max_weight==0,+ *                no upper limit is used.  If min_weight==0, max_weight must+ *                also be 0.+ *   maximal    - require cliques to be maximal cliques+ *   opts       - time printing and clique storage options+ *+ * Returns the number of cliques found.  This can be less than the number+ * of cliques in the graph iff opts->time_function() or opts->user_function()+ * returns FALSE (request abort).+ *+ * The cliques found are stored in opts->clique_list[] and+ * opts->user_function() is called with them (if non-NULL).  The cliques+ * stored in opts->clique_list[] are newly allocated, and can be freed+ * by set_free().+ *+ * Note: Automatically uses clique_unweighted_find_all if all vertex+ *       weights are the same.+ */+int clique_find_all(graph_t *g, int min_weight, int max_weight,+		    boolean maximal, clique_options *opts) {+	int i,n;+	int *table;++	ENTRANCE_SAVE();+	entrance_level++;++	if (opts==NULL)+		opts=&clique_default_options;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(g!=NULL);+	ASSERT(min_weight>=0);+	ASSERT(max_weight>=0);+	ASSERT((max_weight==0) || (min_weight <= max_weight));+	ASSERT(!((min_weight==0) && (max_weight>0)));+	ASSERT((opts->reorder_function==NULL) || (opts->reorder_map==NULL));++	if ((max_weight>0) && (min_weight>max_weight)) {+		/* state was not changed */+		entrance_level--;+		return 0;+	}++    /*+	if (clocks_per_sec==0)+		clocks_per_sec=sysconf(_SC_CLK_TCK);+	ASSERT(clocks_per_sec>0);+    */++	if (!graph_weighted(g)) {+		min_weight=DIV_UP(min_weight,g->weights[0]);+		if (max_weight) {+			max_weight=DIV_DOWN(max_weight,g->weights[0]);+			if (max_weight < min_weight) {+				/* state was not changed */+				entrance_level--;+				return 0;+			}+		}+		+		weight_multiplier = g->weights[0];+		entrance_level--;+		i=clique_unweighted_find_all(g,min_weight,max_weight,maximal,+					     opts);+		ENTRANCE_RESTORE();+		return i;+	}++	/* Dynamic allocation */+	current_clique=set_new(g->n);+	best_clique=set_new(g->n);+	clique_size=malloc(g->n * sizeof(int));+	memset(clique_size, 0, g->n * sizeof(int));+	/* table allocated later */+	temp_list=malloc((g->n+2)*sizeof(int *));+	temp_count=0;++	/* "start clock" */+    /*+	gettimeofday(&realtimer,NULL);+	times(&cputimer);+    */++	/* reorder */+	if (opts->reorder_function) {+		table=opts->reorder_function(g,TRUE);+	} else if (opts->reorder_map) {+		table=reorder_duplicate(opts->reorder_map,g->n);+	} else {+		table=reorder_ident(g->n);+	}+	ASSERT(reorder_is_bijection(table,g->n));++	/* First phase */+	n=weighted_clique_search_single(table,min_weight,INT_MAX,g,opts);+	if (n==0) {+		/* Requested clique has not been found. */+		goto cleanreturn;+	}++	if (min_weight==0) {+		min_weight=n;+		max_weight=n;+		maximal=FALSE;  /* They're maximum cliques already. */+	}+	if (max_weight==0)+		max_weight=INT_MAX;++	for (i=0; i < g->n; i++)+		if ((clique_size[table[i]] >= min_weight) ||+		    (clique_size[table[i]] == 0))+			break;++	/* Second phase */+	n=weighted_clique_search_all(table,i,min_weight,max_weight,maximal,+				     g,opts);++      cleanreturn:+	/* Free resources */+	for (i=0; i < temp_count; i++)+		free(temp_list[i]);+	free(temp_list);+	free(table);+	set_free(current_clique);+	set_free(best_clique);+	free(clique_size);++	ENTRANCE_RESTORE();+	entrance_level--;++	return n;+}+++++++++++++++++#if 0+/*+ * clique_print_time()+ *+ * Reports current running information every 0.1 seconds or when values+ * change.+ *+ *   level    - re-entrance level+ *   i        - current recursion level+ *   n        - maximum recursion level+ *   max      - weight of heaviest clique found+ *   cputime  - CPU time used in algorithm so far+ *   realtime - real time used in algorithm so far+ *   opts     - prints information to (FILE *)opts->output (or stdout if NULL)+ *+ * Returns always TRUE  (ie. never requests abort).+ */+boolean clique_print_time(int level, int i, int n, int max,+			  double cputime, double realtime,+			  clique_options *opts) {+	static float prev_time=100;+	static int prev_i=100;+	static int prev_max=100;+	static int prev_level=0;+	FILE *fp=opts->output;+	int j;++	if (fp==NULL)+		fp=stdout;++	if (ABS(prev_time-realtime)>0.1 || i==n || i<prev_i || max!=prev_max ||+	    level!=prev_level) {+		for (j=1; j<level; j++)+			fprintf(fp,"  ");+		if (realtime-prev_time < 0.01 || i<=prev_i)+			fprintf(fp,"%3d/%d (max %2d)  %2.2f s  "+				"(0.00 s/round)\n",i,n,max,+				realtime);+		else+			fprintf(fp,"%3d/%d (max %2d)  %2.2f s  "+				"(%2.2f s/round)\n",+				i,n,max,realtime,+				(realtime-prev_time)/(i-prev_i));+		prev_time=realtime;+		prev_i=i;+		prev_max=max;+		prev_level=level;+	}+	return TRUE;+}++/*+ * clique_print_time_always()+ *+ * Reports current running information.+ *+ *   level    - re-entrance level+ *   i        - current recursion level+ *   n        - maximum recursion level+ *   max      - largest clique found+ *   cputime  - CPU time used in algorithm so far+ *   realtime - real time used in algorithm so far+ *   opts     - prints information to (FILE *)opts->output (or stdout if NULL)+ *+ * Returns always TRUE  (ie. never requests abort).+ */+boolean clique_print_time_always(int level, int i, int n, int max,+				 double cputime, double realtime,+				 clique_options *opts) {+	static float prev_time=100;+	static int prev_i=100;+	FILE *fp=opts->output;+	int j;++	if (fp==NULL)+		fp=stdout;++	for (j=1; j<level; j++)+		fprintf(fp,"  ");++	if (realtime-prev_time < 0.01 || i<=prev_i)+		fprintf(fp,"%3d/%d (max %2d)  %2.2f s  (0.00 s/round)\n",+			i,n,max,realtime);+	else+		fprintf(fp,"%3d/%d (max %2d)  %2.2f s  (%2.2f s/round)\n",+			i,n,max,realtime,(realtime-prev_time)/(i-prev_i));+	prev_time=realtime;+	prev_i=i;++	return TRUE;+}+#endif
+ igraph/src/cliquer_graph.c view
@@ -0,0 +1,768 @@++/*+ * This file contains the graph handling routines.+ *+ * Copyright (C) 2002 Sampo Niskanen, Patric Östergård.+ * Licensed under the GNU GPL, read the file LICENSE for details.+ */+++#include <stdio.h>+#include <ctype.h>+#include <string.h>+#include "graph.h"++#ifdef USING_R+#include <R.h>+#endif++/*+static graph_t *graph_read_dimacs_binary(FILE *fp,char *firstline);+static graph_t *graph_read_dimacs_ascii(FILE *fp,char *firstline);+*/+++/*+ * graph_new()+ *+ * Returns a newly allocated graph with n vertices all with weight 1,+ * and no edges.+ */+graph_t *graph_new(int n) {+	graph_t *g;+	int i;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(n>0);++	g=malloc(sizeof(graph_t));+	g->n=n;+	g->edges=malloc(g->n * sizeof(set_t));+	g->weights=malloc(g->n * sizeof(int));+	for (i=0; i < g->n; i++) {+		g->edges[i]=set_new(n);+		g->weights[i]=1;+	}+	return g;+}++/*+ * graph_free()+ *+ * Frees the memory associated with the graph g.+ */+void graph_free(graph_t *g) {+	int i;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(g!=NULL);+	ASSERT(g->n > 0);++	for (i=0; i < g->n; i++) {+		set_free(g->edges[i]);+	}+	free(g->weights);+	free(g->edges);+	free(g);+	return;+}+++/*+ * graph_resize()+ *+ * Resizes graph g to given size.  If size > g->n, the new vertices are+ * not connected to any others and their weights are set to 1.+ * If size < g->n, the last g->n - size vertices are removed.+ */+void graph_resize(graph_t *g, int size) {+	int i;++	ASSERT(g!=NULL);+	ASSERT(g->n > 0);+	ASSERT(size > 0);++	if (g->n == size)+		return;++	/* Free/alloc extra edge-sets */+	for (i=size; i < g->n; i++)+		set_free(g->edges[i]);+	g->edges=realloc(g->edges, size * sizeof(set_t));+	for (i=g->n; i < size; i++)+		g->edges[i]=set_new(size);++	/* Resize original sets */+	for (i=0; i < MIN(g->n,size); i++) {+		g->edges[i]=set_resize(g->edges[i],size);+	}++	/* Weights */+	g->weights=realloc(g->weights,size * sizeof(int));+	for (i=g->n; i<size; i++)+		g->weights[i]=1;+	+	g->n=size;+	return;+}++/*+ * graph_crop()+ *+ * Resizes the graph so as to remove all highest-valued isolated vertices.+ */+void graph_crop(graph_t *g) {+	int i;+	+	for (i=g->n-1; i>=1; i--)+		if (set_size(g->edges[i])>0)+			break;+	graph_resize(g,i+1);+	return;+}+++/*+ * graph_weighted()+ *+ * Returns TRUE if all vertex weights of graph g are all the same.+ *+ * Note: Does NOT require weights to be 1.+ */+boolean graph_weighted(graph_t *g) {+	int i,w;++	w=g->weights[0];+	for (i=1; i < g->n; i++)+		if (g->weights[i] != w)+			return TRUE;+	return FALSE;+}++/*+ * graph_edge_count()+ *+ * Returns the number of edges in graph g.+ */+int graph_edge_count(graph_t *g) {+	int i;+	int count=0;++	for (i=0; i < g->n; i++) {+		count += set_size(g->edges[i]);+	}+	return count/2;+}+++#if 0+/*+ * graph_write_dimacs_ascii_file()+ *+ * Writes an ASCII dimacs-format file of graph g, with comment, to+ * given file.+ *+ * Returns TRUE if successful, FALSE if an error occurred.+ */+boolean graph_write_dimacs_ascii_file(graph_t *g, char *comment, char *file) {+	FILE *fp;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(file!=NULL);++	if ((fp=fopen(file,"wb"))==NULL)+		return FALSE;+	if (!graph_write_dimacs_ascii(g,comment,fp)) {+		fclose(fp);+		return FALSE;+	}+	fclose(fp);+	return TRUE;+}++/*+ * graph_write_dimacs_ascii()+ *+ * Writes an ASCII dimacs-format file of graph g, with comment, to the+ * file stream fp.+ *+ * Returns TRUE if successful, FALSE if an error occurred.+ */+boolean graph_write_dimacs_ascii(graph_t *g, char *comment, FILE *fp) {+	int i,j;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(graph_test(g,NULL));+	ASSERT(fp!=NULL);++	if (comment)+		fprintf(fp,"c %s\n",comment);+	fprintf(fp,"p edge %d %d\n",g->n,graph_edge_count(g));+	for (i=0; i < g->n; i++)+		if (g->weights[i]!=1)+			fprintf(fp,"n %d %d\n",i+1,g->weights[i]);+	for (i=0; i < g->n; i++)+		for (j=0; j<i; j++)+			if (GRAPH_IS_EDGE_FAST(g,i,j))+				fprintf(fp,"e %d %d\n",i+1,j+1);+	return TRUE;+}++/*+ * graph_write_dimacs_binary_file()+ *+ * Writes a binary dimacs-format file of graph g, with comment, to+ * given file.+ *+ * Returns TRUE if successful, FALSE if an error occurred.+ */+boolean graph_write_dimacs_binary_file(graph_t *g, char *comment, char *file) {+	FILE *fp;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(file!=NULL);++	if ((fp=fopen(file,"wb"))==NULL)+		return FALSE;+	if (!graph_write_dimacs_binary(g,comment,fp)) {+		fclose(fp);+		return FALSE;+	}+	fclose(fp);+	return TRUE;+}++/*+ * graph_write_dimacs_binary()+ *+ * Writes a binary dimacs-format file of graph g, with comment, to the+ * file stream fp.+ *+ * Returns TRUE if successful, FALSE if an error occurred.+ */++#define STR_APPEND(s) \+if (headerlength+strlen(s) >= headersize) {  \+	headersize+=1024;                    \+	header=realloc(header,headersize);   \+}                                            \+strncat(header,s,1000);                      \+headerlength+=strlen(s);++boolean graph_write_dimacs_binary(graph_t *g, char *comment,FILE *fp) {+	char *buf;+	char *header=NULL;+	int headersize=0;+	int headerlength=0;+	int i,j;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(graph_test(g,NULL));+	ASSERT(fp!=NULL);++	buf=malloc(MAX(1024,g->n/8+1));+	header=malloc(1024);+	header[0]=0;+	headersize=1024;+	if (comment) {+		strcpy(buf,"c ");+		strncat(buf,comment,1000);+		strcat(buf,"\n");+		STR_APPEND(buf);+	}+	sprintf(buf,"p edge %d %d\n",g->n,graph_edge_count(g));+	STR_APPEND(buf);+	for (i=0; i < g->n; i++) {+		if (g->weights[i]!=1) {+			sprintf(buf,"n %d %d\n",i+1,g->weights[i]);+			STR_APPEND(buf);+		}+	}++	fprintf(fp,"%d\n",(int)strlen(header));+	fprintf(fp,"%s",header);+	free(header);++	for (i=0; i < g->n; i++) {+		memset(buf,0,i/8+1);+		for (j=0; j<i; j++) {+			if (GRAPH_IS_EDGE_FAST(g,i,j)) {+				buf[j/8] |= SET_BIT_MASK(7-j%8);+			}+		}+		fwrite(buf,1,i/8+1,fp);+	}+	free(buf);+	return TRUE;+}++++/*+ * graph_read_dimacs_file()+ *+ * Reads a dimacs-format (ASCII or binary) file from the given file.+ *+ * Returns a newly allocated graph, or NULL if an error occurred, and an+ * error message is printed to stderr.+ */+graph_t *graph_read_dimacs_file(char *file) {+	FILE *fp;+	graph_t *g;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(file!=NULL);++	if ((fp=fopen(file,"rb"))==NULL) {+		perror(file);+		return NULL;+	}+	g=graph_read_dimacs(fp);+	fclose(fp);+	return g;+}+++/*+ * graph_read_dimacs()+ *+ * Reads a dimacs-format (ASCII or binary) file from the file stream fp.+ *+ * Returns a newly allocated graph, or NULL if an error occurred, and an+ * error message is printed to stderr.+ */+graph_t *graph_read_dimacs(FILE *fp) {+	char buffer[1024];+	graph_t *g;+	char tmp[10];+	int n;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);+	ASSERT(fp!=NULL);++	if (fgets(buffer,1023,fp)==NULL) {+		fprintf(stderr,"Input does not contain any data.\n");+		return NULL;+	}+	if (sscanf(buffer," %d %2s",&n,tmp)!=1) {+		g=graph_read_dimacs_ascii(fp,buffer);+	} else {+		g=graph_read_dimacs_binary(fp,buffer);+	}+	return g;+}	+++/*+ * parse_input()+ *+ * Parses the string str for ASCII-format dimacs commands, and modifies+ * the graph g accordingly.+ *+ * Returns TRUE if successful, FALSE if a bad command was encountered.+ *+ * Note: Ignores all unknown commands.  The 'd', 'v' and 'x' commands+ *       (mainly generator-specific information) are ignored silently,+ *       for all others a warning message is printed to stderr.+ */+static boolean parse_input(char *str,graph_t *g) {+	int i,j,w;+	char tmp[16];++	for (i=0; i<strlen(str); i++) {+		if (!isspace((int)str[i]))+			break;+	}+	if (i>=strlen(str))  /* blank line */+		return TRUE;+	if (str[i+1]!=0 && !isspace(str[i+1]))  /* not 1-char field */+		return FALSE;++	switch (str[i]) {+	case 'c':+		return TRUE;+	case 'p':+		if (g->n != 0)+			return FALSE;+		if (sscanf(str," p %15s %d %d %2s",tmp,&(g->n),&i,tmp)!=3)+			return FALSE;+		if (g->n <= 0)+			return FALSE;+		g->edges=calloc(g->n,sizeof(set_t));+		for (i=0; i<g->n; i++)+			g->edges[i]=set_new(g->n);+		g->weights=calloc(g->n,sizeof(int));+		for (i=0; i<g->n; i++)+			g->weights[i]=1;+		return TRUE;+	case 'n':+		if ((g->n <= 0) || (g->weights == NULL))+			return FALSE;+		if (sscanf(str," n %d %d %2s",&i,&w,tmp)!=2)+			return FALSE;+		if (i<1 || i>g->n)+			return FALSE;+		if (w<=0)+			return FALSE;+		g->weights[i-1]=w;+		return TRUE;+	case 'e':+		if ((g->n <= 0) || (g->edges == NULL))+			return FALSE;+		if (sscanf(str," e %d %d %2s",&i,&j,tmp)!=2)+			return FALSE;+		if (i<1 || j<1 || i>g->n || j>g->n)+			return FALSE;+		if (i==j)   /* We want antireflexive graphs. */+			return TRUE;+		GRAPH_ADD_EDGE(g,i-1,j-1);+		return TRUE;+	case 'd':+	case 'v':+	case 'x':+		return TRUE;+	default:+		fprintf(stderr,"Warning: ignoring field '%c' in "+			"input.\n",str[i]);+		return TRUE;+	}+}+++/*+ * graph_read_dimacs_binary()+ *+ * Reads a dimacs-format binary file from file stream fp with the first+ * line being firstline.+ *+ * Returns the newly-allocated graph or NULL if an error occurred.+ *+ * TODO: This function leaks memory when reading erroneous files.+ */+static graph_t *graph_read_dimacs_binary(FILE *fp,char *firstline) {+	int length=0;+	graph_t *g;+	int i,j;+	char *buffer;+	char *start;+	char *end;+	char **buf;+	char tmp[10];++	if (sscanf(firstline," %d %2s",&length,tmp)!=1)+		return NULL;+	if (length<=0) {+		fprintf(stderr,"Malformed preamble: preamble size < 0.\n");+		return NULL;+	}+	buffer=malloc(length+2);+	if (fread(buffer,1,length,fp)<length) {+		fprintf(stderr,"Malformed preamble: unexpected "+			"end of file.\n");+		free(buffer);+		return NULL;+	}++	g=calloc(1,sizeof(graph_t));+	start=buffer;+	while (start < buffer+length) {+		end=strchr(start,'\n');+		if (end==NULL)+			end=buffer+length;+		end[0]=0;+		if (!parse_input(start,g)) {+			fprintf(stderr,"Malformed preamble: %s\n",start);+			free (buffer);+			return NULL;+		}+		start=end+1;+	}++	free(buffer);+	if (g->n <= 0) {+		fprintf(stderr,"Malformed preamble: number of "+			"vertices <= 0\n");+		free(g);+		return NULL;+	}++	/* Binary part. */+	buf=calloc(g->n,sizeof(char*));+	for (i=0; i < g->n; i++) {+		buf[i]=calloc(g->n,1);+		if (fread(buf[i],1,i/8+1,fp) < (i/8+1)) {+			fprintf(stderr,"Unexpected end of file when "+				"reading graph.\n");+			return NULL;+		}+	}++	for (i=0; i < g->n; i++) {+		for (j=0; j<i; j++) {+			if (buf[i][j/8]&(1<<(7-(j%8)))) {+				GRAPH_ADD_EDGE(g,i,j);+			}+		}+		free(buf[i]);+	}+	free(buf);++	return g;+}+++/*+ * graph_read_dimacs_ascii()+ *+ * Reads a dimacs-format ASCII file from file stream fp with the first+ * line being firstline.+ *+ * Returns the newly-allocated graph or NULL if an error occurred.+ *+ * TODO:  This function leaks memory when reading erroneous files.+ */+static graph_t *graph_read_dimacs_ascii(FILE *fp, char *firstline) {+	graph_t *g;+	char buffer[1024];++	g=calloc(1,sizeof(graph_t));++	if (!parse_input(firstline,g)) {+		fprintf(stderr,"Malformed input: %s",firstline);+		free(g);+		return NULL;+	}+	while (fgets(buffer,1023,fp)) {+		if (!parse_input(buffer,g)) {+			fprintf(stderr,"Malformed input: %s",buffer);+			return NULL;+		}+	}+	if (g->n <= 0) {+		free(g);+		fprintf(stderr,"Unexpected end of file when reading graph.\n");+		return NULL;+	}++	return g;+}+#endif+++#ifndef USING_R+/*+ * graph_print()+ *+ * Prints a representation of the graph g to stdout (along with any errors+ * noticed).  Mainly useful for debugging purposes and trivial output.+ *+ * The output consists of a first line describing the dimensions and then+ * one line per vertex containing the vertex number (numbered 0,...,n-1),+ * the vertex weight (if the graph is weighted), "->" and then a list+ * of all vertices it is adjacent to.+ */+void graph_print(graph_t *g) {+	int i,j;+	int asymm=0;+	int refl=0;+	int nonpos=0;+	int extra=0;+	unsigned int weight=0;+	boolean weighted;+	+	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);++	if (g==NULL) {+		printf("   WARNING: Graph pointer is NULL!\n");+		return;+	}+	if (g->n <= 0) {+		printf("   WARNING: Graph has %d vertices "+		       "(should be positive)!\n",g->n);+		return;+	}+	+	weighted=graph_weighted(g);++	printf("%s graph has %d vertices, %d edges (density %.2f).\n",+	       weighted?"Weighted":((g->weights[0]==1)?+				    "Unweighted":"Semi-weighted"),+	       g->n,graph_edge_count(g),+	       (float)graph_edge_count(g)/((float)(g->n - 1)*(g->n)/2));++	for (i=0; i < g->n; i++) {+		printf("%2d",i);+		if (weighted) {+			printf(" w=%d",g->weights[i]);+			if (g->weights[i] <= 0) {+				printf("*NON-POSITIVE*");+				nonpos++;+			}+		}+		if (weight < INT_MAX)+			weight+=g->weights[i];+		printf(" ->");+		for (j=0; j < g->n; j++) {+			if (SET_CONTAINS_FAST(g->edges[i],j)) {+				printf(" %d",j);+				if (i==j) {+					printf("*REFLEXIVE*");+					refl++;+				}+				if (!SET_CONTAINS_FAST(g->edges[j],i)) {+					printf("*ASYMMERTIC*");+					asymm++;+				}+			}+		}+		for (j=g->n; j < SET_ARRAY_LENGTH(g->edges[i])*ELEMENTSIZE;+		     j++) {+			if (SET_CONTAINS_FAST(g->edges[i],j)) {+				printf(" %d*NON-EXISTENT*",j);+				extra++;+			}+		}+		printf("\n");+	}++	if (asymm)+		printf("   WARNING: Graph contained %d asymmetric edges!\n",+		       asymm);+	if (refl)+		printf("   WARNING: Graph contained %d reflexive edges!\n",+		       refl);+	if (nonpos)+		printf("   WARNING: Graph contained %d non-positive vertex "+		       "weights!\n",nonpos);+	if (extra)+		printf("   WARNING: Graph contained %d edges to "+		       "non-existent vertices!\n",extra);+	if (weight>=INT_MAX)+		printf("   WARNING: Total graph weight >= INT_MAX!\n");+	return;+}++#endif++/*+ * graph_test()+ *+ * Tests graph g to be valid.  Checks that g is non-NULL, the edges are+ * symmetric and anti-reflexive, and that all vertex weights are positive.+ * If output is non-NULL, prints a few lines telling the status of the graph+ * to file descriptor output.+ * + * Returns TRUE if the graph is valid, FALSE otherwise.+ */+boolean graph_test(graph_t *g,FILE *output) {+	int i,j;+	int edges=0;+	int asymm=0;+	int nonpos=0;+	int refl=0;+	int extra=0;+	unsigned int weight=0;+	boolean weighted;++	ASSERT((sizeof(setelement)*8)==ELEMENTSIZE);++	if (g==NULL) {+		if (output)+			fprintf(output,"   WARNING: Graph pointer is NULL!\n");+		return FALSE;+	}++	weighted=graph_weighted(g);+	+	for (i=0; i < g->n; i++) {+		if (g->edges[i]==NULL) {+			if (output)+				fprintf(output,"   WARNING: Graph edge set "+					"NULL!\n"+					"   (further warning suppressed)\n");+			return FALSE;+		}+		if (SET_MAX_SIZE(g->edges[i]) < g->n) {+			if (output)+				fprintf(output,"   WARNING: Graph edge set "+					"too small!\n"+					"   (further warnings suppressed)\n");+			return FALSE;+		}+		for (j=0; j < g->n; j++) {+			if (SET_CONTAINS_FAST(g->edges[i],j)) {+				edges++;+				if (i==j) {+					refl++;+				}+				if (!SET_CONTAINS_FAST(g->edges[j],i)) {+					asymm++;+				}+			}+		}+		for (j=g->n; j < SET_ARRAY_LENGTH(g->edges[i])*ELEMENTSIZE;+		     j++) {+			if (SET_CONTAINS_FAST(g->edges[i],j))+				extra++;+		}+		if (g->weights[i] <= 0)+			nonpos++;+		if (weight<INT_MAX)+			weight += g->weights[i];+	}+	+	edges/=2;  /* Each is counted twice. */+	+	if (output) {+		/* Semi-weighted means all weights are equal, but not 1. */+		fprintf(output,"%s graph has %d vertices, %d edges "+			"(density %.2f).\n",+			weighted?"Weighted":+			((g->weights[0]==1)?"Unweighted":"Semi-weighted"),+			g->n,edges,(float)edges/((float)(g->n - 1)*(g->n)/2));+		+		if (asymm)+			fprintf(output,"   WARNING: Graph contained %d "+				"asymmetric edges!\n",asymm);+		if (refl)+			fprintf(output,"   WARNING: Graph contained %d "+				"reflexive edges!\n",refl);+		if (nonpos)+			fprintf(output,"   WARNING: Graph contained %d "+				"non-positive vertex weights!\n",nonpos);+		if (extra)+			fprintf(output,"   WARNING: Graph contained %d edges "+				"to non-existent vertices!\n",extra);+		if (weight>=INT_MAX)+			fprintf(output,"   WARNING: Total graph weight >= "+				"INT_MAX!\n");+		if (asymm==0 && refl==0 && nonpos==0 && extra==0 &&+		    weight<INT_MAX)+			fprintf(output,"Graph OK.\n");+	}+	+	if (asymm || refl || nonpos || extra || weight>=INT_MAX)+		return FALSE;++	return TRUE;+}+++/*+ * graph_test_regular()+ *+ * Returns the vertex degree for regular graphs, or -1 if the graph is+ * not regular.+ */+int graph_test_regular(graph_t *g) {+	int i,n;++	n=set_size(g->edges[0]);++	for (i=1; i < g->n; i++) {+		if (set_size(g->edges[i]) != n)+			return -1;+	}+	return n;+}+
+ igraph/src/cliques.c view
@@ -0,0 +1,1399 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "igraph_cliquer.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_cliquer_cliques(graph, res, min_size, max_size);+}+++/**+ * \function igraph_clique_size_hist+ * \brief Count cliques of each size in the graph+ *+ * </para><para>+ * Cliques are fully connected subgraphs of a graph.+ *+ * </para><para>The current implementation of this function+ * uses version 1.21 of the Cliquer library by Sampo Niskanen and+ * Patric R. J. Östergård, http://users.aalto.fi/~pat/cliquer.html+ *+ * \param graph The input graph.+ * \param hist Pointer to an initialized vector. The result will be stored+ * here. The first element will store the number of size-1 cliques, the second+ * element the number of size-2 cliques, etc.  For cliques smaller than \c min_size,+ * zero counts will be returned.+ * \param min_size Integer giving the minimum size of the cliques to be+ *   returned. If negative or zero, no lower bound will be used.+ * \param max_size Integer giving the maximum size of the cliques to be+ *   returned. If negative or zero, no upper bound will be used.+ * \return Error code.+ *+ * \sa \ref igraph_cliques() and \ref igraph_cliques_callback()+ *+ * Time complexity: Exponential+ *+ */+int igraph_clique_size_hist(const igraph_t *graph, igraph_vector_t *hist,+                            igraph_integer_t min_size, igraph_integer_t max_size) {+    return igraph_i_cliquer_histogram(graph, hist, min_size, max_size);+}+++/**+ * \function igraph_cliques_callback+ * \brief Calls a function for each clique in the graph.+ *+ * </para><para>+ * Cliques are fully connected subgraphs of a graph. This function+ * enumerates all cliques within the given size range and calls+ * \p cliquehandler_fn for each of them. The cliques are passed to the+ * callback function as an <type>igraph_vector_t *</type>.  Destroying and+ * freeing this vector is left up to the user.  Use \ref igraph_vector_destroy()+ * to destroy it first, then free it using \ref igraph_free().+ *+ * </para><para>The current implementation of this function+ * uses version 1.21 of the Cliquer library by Sampo Niskanen and+ * Patric R. J. Östergård, http://users.aalto.fi/~pat/cliquer.html+ *+ * \param graph The input graph.+ * \param 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.+ * \param cliquehandler_fn Callback function to be called for each clique.+ * See also igraph_clique_handler_t.+ * \param arg Extra argument to supply to \p cliquehandler_fn.+ * \return Error code.+ *+ * \sa \ref igraph_cliques()+ *+ * Time complexity: Exponential+ *+ */+int igraph_cliques_callback(const igraph_t *graph,+                            igraph_integer_t min_size, igraph_integer_t max_size,+                            igraph_clique_handler_t *cliquehandler_fn, void *arg) {+    return igraph_i_cliquer_callback(graph, min_size, max_size, cliquehandler_fn, arg);+}+++/**+ * \function igraph_weighted_cliques+ * \brief Find all cliques in a given weight range in a vertex weighted graph+ *+ * </para><para>+ * Cliques are fully connected subgraphs of a graph.+ * The weight of a clique is the sum of the weights+ * of individual vertices within the clique.+ *+ * </para><para>The current implementation of this function+ * uses version 1.21 of the Cliquer library by Sampo Niskanen and+ * Patric R. J. Östergård, http://users.aalto.fi/~pat/cliquer.html+ *+ * Only positive integer vertex weights are supported.+ *+ * \param graph The input graph.+ * \param vertex_weights A vector of vertex weights. The current implementation+ *   will truncate all weights to their integer parts.+ * \param res Pointer to a pointer vector, the result will be stored+ *   here, ie. \c res will contain pointers to \c igraph_vector_t+ *   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_weight Integer giving the minimum weight of the cliques to be+ *   returned. If negative or zero, no lower bound will be used.+ * \param max_weight Integer giving the maximum weight of the cliques to be+ *   returned. If negative or zero, no upper bound will be used.+ * \param maximal If true, only maximal cliques will be returned+ * \return Error code.+ *+ * \sa \ref igraph_cliques(), \ref igraph_maximal_cliques()+ *+ * Time complexity: Exponential+ *+ */+int igraph_weighted_cliques(const igraph_t *graph,+                            const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res,+                            igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal) {+    return igraph_i_weighted_cliques(graph, vertex_weights, res, min_weight, max_weight, maximal);+}+++/**+ * \function igraph_largest_weighted_cliques+ * \brief Finds the largest weight clique(s) in a graph.+ *+ * </para><para>+ * Finds the clique(s) having the largest weight in the graph.+ *+ * </para><para>The current implementation of this function+ * uses version 1.21 of the Cliquer library by Sampo Niskanen and+ * Patric R. J. Östergård, http://users.aalto.fi/~pat/cliquer.html+ *+ * Only positive integer vertex weights are supported.+ *+ * \param graph The input graph.+ * \param vertex_weights A vector of vertex weights. The current implementation+ *   will truncate all weights to their integer parts.+ * \param res Pointer to a pointer vector, the result will be stored+ *   here, ie. \c res will contain pointers to \c igraph_vector_t+ *   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.+ * \return Error code.+ *+ * \sa \ref igraph_weighted_cliques(), \ref igraph_weighted_clique_number(), \ref igraph_largest_cliques()+ *+ * Time complexity: TODO+ */+int igraph_largest_weighted_cliques(const igraph_t *graph,+                                    const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res) {+    return igraph_i_largest_weighted_cliques(graph, vertex_weights, res);+}+++/**+ * \function igraph_weighted_clique_number+ * \brief Find the weight of the largest weight clique in the graph+ *+ * </para><para>The current implementation of this function+ * uses version 1.21 of the Cliquer library by Sampo Niskanen and+ * Patric R. J. Östergård, http://users.aalto.fi/~pat/cliquer.html+ *+ * Only positive integer vertex weights are supported.+ *+ * \param graph The input graph.+ * \param vertex_weights A vector of vertex weights. The current implementation+ *   will truncate all weights to their integer parts.+ * \param res The largest weight will be returned to the \c igraph_real_t+ *   pointed to by this variable.+ * \return Error code.+ *+ * \sa \ref igraph_weighted_cliques(), \ref igraph_largest_weighted_cliques(), \ref igraph_clique_number()+ *+ * Time complexity: TODO+ *+ */+int igraph_weighted_clique_number(const igraph_t *graph,+                                  const igraph_vector_t *vertex_weights, igraph_real_t *res) {+    return igraph_i_weighted_clique_number(graph, vertex_weights, res);+}++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;+}
+ igraph/src/close.c view
@@ -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
+ igraph/src/clustertool.cpp view
@@ -0,0 +1,693 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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 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);+    }++    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);+    }++    if (weights) {+        igraph_vector_minmax(weights, &d_n, &d_p);+    } else {+        d_n = d_p = 1;+    }++    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;+}
+ igraph/src/cocitation.c view
@@ -0,0 +1,780 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R package.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}+
+ igraph/src/cohesive_blocks.c view
@@ -0,0 +1,612 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_bool_t is_simple;++    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_CHECK(igraph_is_simple(graph, &is_simple));+    if (!is_simple) {+        IGRAPH_ERROR("Cohesive blocking only works on simple 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;+}
+ igraph/src/coloring.c view
@@ -0,0 +1,142 @@++#include "igraph_coloring.h"+#include "igraph_interface.h"+#include "igraph_adjlist.h"+#include "igraph_interrupt_internal.h"+#include "igraph_types_internal.h"+++int igraph_i_vertex_coloring_greedy_cn(const igraph_t *graph, igraph_vector_int_t *colors) {+    long i, vertex, maxdeg;+    long vc = igraph_vcount(graph);+    igraph_2wheap_t cn; /* indexed heap storing number of already coloured neighbours */+    igraph_vector_int_t neigh_colors;+    igraph_adjlist_t adjlist;++    IGRAPH_CHECK(igraph_vector_int_resize(colors, vc));+    igraph_vector_int_fill(colors, 0);++    /* Nothing to do for 0 or 1 vertices.+     * Remember that colours are integers starting from 0,+     * and the 'colors' vector is already 0-initialized above.+     */+    if (vc <= 1) {+        return IGRAPH_SUCCESS;+    }++    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_ALL));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);++    /* find maximum degree and a corresponding vertex */+    {+        igraph_vector_t degree;++        IGRAPH_CHECK(igraph_vector_init(&degree, 0));+        IGRAPH_FINALLY(igraph_vector_destroy, &degree);+        IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), IGRAPH_ALL, 0));++        vertex = igraph_vector_which_max(&degree);+        maxdeg = VECTOR(degree)[vertex];++        igraph_vector_destroy(&degree);+        IGRAPH_FINALLY_CLEAN(1);+    }++    IGRAPH_CHECK(igraph_vector_int_init(&neigh_colors, 0));+    IGRAPH_CHECK(igraph_vector_int_reserve(&neigh_colors, maxdeg));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &neigh_colors);++    IGRAPH_CHECK(igraph_2wheap_init(&cn, vc));+    IGRAPH_FINALLY(igraph_2wheap_destroy, &cn);+    for (i = 0; i < vc; ++i)+        if (i != vertex) {+            igraph_2wheap_push_with_index(&cn, i, 0);    /* should not fail since memory was already reserved */+        }++    while (1) {+        igraph_vector_int_t *neighbors = igraph_adjlist_get(&adjlist, vertex);+        long neigh_count = igraph_vector_int_size(neighbors);++        /* colour current vertex */+        {+            igraph_integer_t col;++            IGRAPH_CHECK(igraph_vector_int_resize(&neigh_colors, neigh_count));+            for (i = 0; i < neigh_count; ++i) {+                VECTOR(neigh_colors)[i] = VECTOR(*colors)[ VECTOR(*neighbors)[i] ];+            }+            igraph_vector_int_sort(&neigh_colors);++            i = 0;+            col = 0;+            do {+                while (i < neigh_count && VECTOR(neigh_colors)[i] == col) {+                    i++;+                }+                col++;+            } while (i < neigh_count && VECTOR(neigh_colors)[i] == col);++            VECTOR(*colors)[vertex] = col;+        }++        /* increment number of coloured neighbours for each neighbour of vertex */+        for (i = 0; i < neigh_count; ++i) {+            long idx = VECTOR(*neighbors)[i];+            if (igraph_2wheap_has_elem(&cn, idx)) {+                igraph_2wheap_modify(&cn, idx, igraph_2wheap_get(&cn, idx) + 1);+            }+        }++        /* stop if no more vertices left to colour */+        if (igraph_2wheap_empty(&cn)) {+            break;+        }++        igraph_2wheap_delete_max_index(&cn, &vertex);++        IGRAPH_ALLOW_INTERRUPTION();+    }++    /* subtract 1 from each colour value, so that colours start at 0 */+    igraph_vector_int_add_constant(colors, -1);++    /* free data structures */+    igraph_vector_int_destroy(&neigh_colors);+    igraph_adjlist_destroy(&adjlist);+    igraph_2wheap_destroy(&cn);+    IGRAPH_FINALLY_CLEAN(3);++    return IGRAPH_SUCCESS;+}+++/**+ * \function igraph_vertex_coloring_greedy+ * \brief Computes a vertex coloring using a greedy algorithm.+ *+ * </para><para>+ * This function assigns a "color"---represented as a non-negative integer---to+ * each vertex of the graph in such a way that neighboring vertices never have+ * the same color. The obtained coloring is not necessarily minimal.+ *+ * </para><para>+ * Vertices are colored one by one, choosing the smallest color index that+ * differs from that of already colored neighbors.+ * Colors are represented with non-negative integers 0, 1, 2, ...+ *+ * \param graph The input graph.+ * \param colors Pointer to an initialized integer vector. The vertex colors will be stored here.+ * \param heuristic The vertex ordering heuristic to use during greedy coloring. See \ref igraph_coloring_greedy_t+ *+ * \return Error code.+ *+ * \example examples/simple/igraph_coloring.c+ */+int igraph_vertex_coloring_greedy(const igraph_t *graph, igraph_vector_int_t *colors, igraph_coloring_greedy_t heuristic) {+    switch (heuristic) {+    case IGRAPH_COLORING_GREEDY_COLORED_NEIGHBORS:+        return igraph_i_vertex_coloring_greedy_cn(graph, colors);+    default:+        return IGRAPH_EINVAL;+    }+}
+ igraph/src/community.c view
@@ -0,0 +1,3840 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "igraph_structural.h"+#include "config.h"++#include <string.h>+#include <math.h>++#ifdef USING_R+    #include <R.h>+#endif++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_int_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);+        }++        if (membership != 0) {+            IGRAPH_WARNING("Membership vector will be selected based on the lowest "\+                           "modularity score.");+        }++        if (modularity != 0 || membership != 0) {+            IGRAPH_WARNING("Modularity calculation with weighted edge betweenness "\+                           "community detection might not make sense -- modularity treats edge "\+                           "weights as similarities while edge betwenness treats them as "\+                           "distances");+        }++        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_int_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_int_size(neip);+                    for (i = 0; i < neino; i++) {+                        long int edge = (long int) VECTOR(*neip)[i];+                        long int neighbor = IGRAPH_OTHER(graph, edge, actnode);+                        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_int_size(neip);++                    for (i = 0; i < neino; i++) {+                        long int edge = VECTOR(*neip)[i];+                        long int to = IGRAPH_OTHER(graph, edge, minnei);+                        igraph_real_t altdist = mindist + VECTOR(*weights)[edge];+                        igraph_real_t curdist = distance[to];+                        igraph_vector_int_t *v;++                        if (curdist == 0) {+                            /* This is the first finite distance to 'to' */+                            v = igraph_inclist_get(&fathers, to);+                            igraph_vector_int_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_int_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_int_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_int_t *fatv = igraph_inclist_get(&fathers, w);+                    long int fatv_len = igraph_vector_int_size(fatv);++                    for (i = 0; i < fatv_len; i++) {+                        long int fedge = (long int) VECTOR(*fatv)[i];+                        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_int_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_int_size(neip);+        igraph_vector_int_search(neip, 0, maxedge, &pos);+        VECTOR(*neip)[pos] = VECTOR(*neip)[neino - 1];+        igraph_vector_int_pop_back(neip);++        neip = igraph_inclist_get(elist_out_p, from);+        neino = igraph_vector_int_size(neip);+        igraph_vector_int_search(neip, 0, maxedge, &pos);+        VECTOR(*neip)[pos] = VECTOR(*neip)[neino - 1];+        igraph_vector_int_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. It must be undirected; directed graphs are+ *     not supported yet.+ * \param membership Numeric vector which gives the type of each+ *     vertex, ie. the component to which it belongs.+ *     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_is_directed(graph)) {+#ifndef USING_R+        IGRAPH_ERROR("modularity is implemented for undirected graphs", IGRAPH_EINVAL);+#else+        REprintf("Modularity is implemented for undirected graphs only.\n");+#endif+    }++    if (igraph_vector_size(membership) < igraph_vcount(graph)) {+        IGRAPH_ERROR("cannot calculate modularity, membership vector too short",+                     IGRAPH_EINVAL);+    }+    if (igraph_vector_min(membership) < 0) {+        IGRAPH_ERROR("Invalid membership vector", 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+ * \brief Calculate the modularity matrix+ *+ * This function returns the modularity matrix defined as+ * `B_ij = A_ij - k_i k_j * / 2 m`+ * where `A_ij` denotes the adjacency matrix, `k_i` is the degree of node `i`+ * and `m` is the total weight in the graph. Note that self-loops are multiplied+ * by 2 in this implementation. If weights are specified, the weighted+ * counterparts are used.+ *+ * \param graph   The input graph+ * \param modmat  Pointer to an initialized matrix in which the modularity+ *                matrix is stored.+ * \param weights Edge weights, pointer to a vector. If this is a null pointer+ *                then every edge is assumed to have a weight of 1.+ */++int igraph_modularity_matrix(const igraph_t *graph,+                             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 (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++) {+        MATRIX(*modmat, i, i) *= 2;+    }+    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. The supplied membership is expected to fall in the+ * range 0, ..., n - 1.+ *+ * \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.+ * \param  nb_clusters Pointer to an integer for the number of+ *                     distinct clusters. If not NULL, this will be+ *                     updated to reflect the number of distinct+ *                     clusters found in membership.+ *+ * Time complexity: should be O(n) for n elements.+ */+int igraph_reindex_membership(igraph_vector_t *membership,+                              igraph_vector_t *new_to_old,+                              igraph_integer_t *nb_clusters) {++    long int i, n = igraph_vector_size(membership);+    igraph_vector_t new_cluster;+    igraph_integer_t i_nb_clusters;++    /* We allow original cluster indices in the range 0, ..., n - 1 */+    IGRAPH_CHECK(igraph_vector_init(&new_cluster, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &new_cluster);++    if (new_to_old) {+        igraph_vector_clear(new_to_old);+    }++    /* Clean clusters. We will store the new cluster + 1 so that membership == 0+     * indicates that no cluster was assigned yet. */+    i_nb_clusters = 1;+    for (i = 0; i < n; i++) {+        long int c = (long int)VECTOR(*membership)[i];++        if (c >= n) {+            IGRAPH_ERROR("Cluster out of range", IGRAPH_EINVAL);+        }++        if (VECTOR(new_cluster)[c] == 0) {+            VECTOR(new_cluster)[c] = (igraph_real_t)i_nb_clusters;+            i_nb_clusters += 1;+            if (new_to_old) {+                IGRAPH_CHECK(igraph_vector_push_back(new_to_old, c));+            }+        }+    }++    /* Assign new membership */+    for (i = 0; i < n; i++) {+        long int c = (long int)VECTOR(*membership)[i];+        VECTOR(*membership)[i] = VECTOR(new_cluster)[c] - 1;+    }+    if (nb_clusters) {+        /* We used the cluster + 1, so correct */+        *nb_clusters = i_nb_clusters - 1;+    }++    igraph_vector_destroy(&new_cluster);++    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}++/********************************************************************/++/**+ * \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. Note that+ * any further refinement, for example using Kernighan-Lin, as+ * proposed in Section V.A of Newman (2006), is not implemented here.+ * </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_int_t *inc = igraph_inclist_get(inclist, oldid);+        nlen = igraph_vector_int_size(inc);+        to[j] = 0.0;+        VECTOR(*tmp)[j] = 0.0;+        for (k = 0; k < nlen; k++) {+            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_int_t *inc = igraph_inclist_get(inclist, oldid);+        nlen = igraph_vector_int_size(inc);+        to[j] = 0.0;+        VECTOR(*tmp)[j] = 0.0;+        for (k = 0; k < nlen; k++) {+            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. Note that we cannot use a+                 * fixed all-1 starting vector as sometimes ARPACK would return a+                 * 'starting vector is zero' error -- this is of course not true but+                 * it's a result of ARPACK >= 3.6.3 trying to force the starting vector+                 * into the range of OP (i.e. the matrix being solved). The initial+                 * vector we use here seems to work, but I have no theoretical argument+                 * for its usage; it just happens to work. */+                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] = i % 2 ? 1 : -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. See the comment a few lines+                 * above about the exact choice of this starting vector */+                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] = i % 2 ? 1 : -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_fluid_communities+ * \brief Community detection algorithm based on the simple idea of+ * several fluids interacting in a non-homogeneous environment+ * (the graph topology), expanding and contracting based on their+ * interaction and density.+ *+ * This function implements the community detection method described in:+ * Parés F, Gasulla DG, et. al. (2018) Fluid Communities: A Competitive,+ * Scalable and Diverse Community Detection Algorithm. In: Complex Networks+ * &amp; Their Applications VI: Proceedings of Complex Networks 2017 (The Sixth+ * International Conference on Complex Networks and Their Applications),+ * Springer, vol 689, p 229.+ *+ * \param graph The input graph. The graph must be simple and connected.+ *   Empty graphs are not supported as well as single vertex graphs.+ *   Edge directions are ignored. Weights are not considered.+ * \param no_of_communities The number of communities to be found. Must be+ *   greater than 0 and fewer than number of vertices in the graph.+ * \param membership The result vector mapping vertices to the communities+ * they are assigned to.+ * \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(|E|)+ *+ * \example examples/tests/igraph_community_fluid_communities.c+ */+int igraph_community_fluid_communities(const igraph_t *graph,+                                       igraph_integer_t no_of_communities,+                                       igraph_vector_t *membership,+                                       igraph_real_t *modularity) {+    /* Declaration of variables */+    long int no_of_nodes, i, j, k, kv1;+    igraph_adjlist_t al;+    double max_density;+    igraph_bool_t res, running;+    igraph_vector_t node_order, density, label_counters, dominant_labels, nonzero_labels;+    igraph_vector_int_t com_to_numvertices;++    /* Initialization of variables needed for initial checking */+    no_of_nodes = igraph_vcount(graph);++    /* Checking input values */+    if (no_of_nodes < 2) {+        IGRAPH_ERROR("Empty and single vertex graphs are not supported.", IGRAPH_EINVAL);+    }+    if ((long int) no_of_communities < 1) {+        IGRAPH_ERROR("'no_of_communities' must be greater than 0.", IGRAPH_EINVAL);+    }+    if ((long int) no_of_communities > no_of_nodes) {+        IGRAPH_ERROR("'no_of_communities' can not be greater than number of nodes in "+                     "the graph.", IGRAPH_EINVAL);+    }+    igraph_is_simple(graph, &res);+    if (!res) {+        IGRAPH_ERROR("Only simple graphs are supported.", IGRAPH_EINVAL);+    }+    igraph_is_connected(graph, &res, IGRAPH_WEAK);+    if (!res) {+        IGRAPH_ERROR("Disconnected graphs are not supported.", IGRAPH_EINVAL);+    }+    if (igraph_is_directed(graph)) {+        IGRAPH_WARNING("Edge directions are ignored.");+    }++    /* Internal variables initialization */+    max_density = 1.0;+    running = 1;++    /* Resize membership vector (number of nodes) */+    IGRAPH_CHECK(igraph_vector_resize(membership, no_of_nodes));++    /* Initialize density and com_to_numvertices vectors */+    IGRAPH_CHECK(igraph_vector_init(&density, (long int) no_of_communities));+    IGRAPH_FINALLY(igraph_vector_destroy, &density);+    IGRAPH_CHECK(igraph_vector_int_init(&com_to_numvertices, (long int) no_of_communities));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &com_to_numvertices);++    /* Initialize node ordering vector */+    IGRAPH_CHECK(igraph_vector_init_seq(&node_order, 0, no_of_nodes - 1));+    IGRAPH_FINALLY(igraph_vector_destroy, &node_order);++    /* Initialize the membership vector with 0 values */+    igraph_vector_null(membership);+    /* Initialize densities to max_density */+    igraph_vector_fill(&density, max_density);++    RNG_BEGIN();++    /* Initialize com_to_numvertices and initialize communities into membership vector */+    IGRAPH_CHECK(igraph_vector_shuffle(&node_order));+    for (i = 0; i < no_of_communities; i++) {+        /* Initialize membership at initial nodes for each community+         * where 0 refers to have no label*/+        VECTOR(*membership)[(long int)VECTOR(node_order)[i]] = i + 1.0;+        /* Initialize com_to_numvertices list: Number of vertices for each community */+        VECTOR(com_to_numvertices)[i] = 1;+    }++    /* Create an adjacency list representation for efficiency. */+    IGRAPH_CHECK(igraph_adjlist_init(graph, &al, IGRAPH_ALL));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &al);++    /* Create storage space for counting distinct labels and dominant ones */+    IGRAPH_VECTOR_INIT_FINALLY(&dominant_labels, (long int) no_of_communities);+    IGRAPH_VECTOR_INIT_FINALLY(&nonzero_labels, (long int) no_of_communities);++    IGRAPH_CHECK(igraph_vector_init(&label_counters, (long int) no_of_communities));+    IGRAPH_FINALLY(igraph_vector_destroy, &label_counters);++    /* running is the convergence boolean variable */+    running = 1;+    while (running) {+        /* Declarations of varibales used inside main loop */+        long int v1, size, rand_idx;+        igraph_real_t max_count, label_counter_diff;+        igraph_vector_int_t *neis;+        igraph_bool_t same_label_in_dominant;++        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_nodes; i++) {+            /* Clear dominant_labels and nonzero_labels vectors */+            igraph_vector_clear(&dominant_labels);+            igraph_vector_null(&label_counters);++            /* Obtain actual node index */+            v1 = (long int) VECTOR(node_order)[i];+            /* Take into account same label in updating rule */+            kv1 = (long int) VECTOR(*membership)[v1];+            max_count = 0.0;+            if (kv1 != 0) {+                VECTOR(label_counters)[kv1 - 1] += VECTOR(density)[kv1 - 1];+                /* Set up max_count */+                max_count = VECTOR(density)[kv1 - 1];+                /* Initialize dominant_labels */+                IGRAPH_CHECK(igraph_vector_resize(&dominant_labels, 1));+                VECTOR(dominant_labels)[0] = kv1;+            }++            /* Count the weights corresponding to different labels */+            neis = igraph_adjlist_get(&al, v1);+            size = igraph_vector_int_size(neis);+            for (j = 0; j < size; j++) {+                k = (long int) VECTOR(*membership)[(long)VECTOR(*neis)[j]];+                /* skip if it has no label yet */+                if (k == 0) {+                    continue;+                }+                /* Update label counter and evaluate diff against max_count*/+                VECTOR(label_counters)[k - 1] += VECTOR(density)[k - 1];+                label_counter_diff = VECTOR(label_counters)[k - 1] - max_count;+                /* Check if this label must be included in dominant_labels vector */+                if (label_counter_diff > 0.0001) {+                    max_count = VECTOR(label_counters)[k - 1];+                    IGRAPH_CHECK(igraph_vector_resize(&dominant_labels, 1));+                    VECTOR(dominant_labels)[0] = k;+                } else if (-0.0001 < label_counter_diff && label_counter_diff < 0.0001) {+                    IGRAPH_CHECK(igraph_vector_push_back(&dominant_labels, k));+                }+            }++            if (!igraph_vector_empty(&dominant_labels)) {+                /* Maintain same label if it exists in dominant_labels */+                same_label_in_dominant = igraph_vector_contains(&dominant_labels, kv1);++                if (!same_label_in_dominant) {+                    /* We need at least one more iteration */+                    running = 1;++                    /* Select randomly from the dominant labels */+                    rand_idx = RNG_INTEGER(0, igraph_vector_size(&dominant_labels) - 1);+                    k = (long int) VECTOR(dominant_labels)[rand_idx];++                    if (kv1 != 0) {+                        /* Subtract 1 vertex from corresponding community in com_to_numvertices */+                        VECTOR(com_to_numvertices)[kv1 - 1] -= 1;+                        /* Re-calculate density for community kv1 */+                        VECTOR(density)[kv1 - 1] = max_density / VECTOR(com_to_numvertices)[kv1 - 1];+                    }++                    /* Update vertex new label */+                    VECTOR(*membership)[v1] = k;++                    /* Add 1 vertex to corresponding new community in com_to_numvertices */+                    VECTOR(com_to_numvertices)[k - 1] += 1;+                    /* Re-calculate density for new community k */+                    VECTOR(density)[k - 1] = max_density / VECTOR(com_to_numvertices)[k - 1];+                }+            }+        }+    }++    RNG_END();+++    /* Shift back the membership vector */+    /* There must be no 0 labels in membership vector at this point */+    for (i = 0; i < no_of_nodes; i++) {+        VECTOR(*membership)[i] -= 1;+        /* Something went wrong: At least one vertex has no community assigned */+        if (VECTOR(*membership)[i] < 0) {+            IGRAPH_ERROR("Something went wrong during execution. One or more vertices got "+                         "no community assigned at algorithm convergence.", IGRAPH_EINTERNAL);+        }+    }++    igraph_adjlist_destroy(&al);+    IGRAPH_FINALLY_CLEAN(1);++    if (modularity) {+        IGRAPH_CHECK(igraph_modularity(graph, membership, modularity,+                                       NULL));+    }++    igraph_vector_destroy(&node_order);+    igraph_vector_destroy(&density);+    igraph_vector_int_destroy(&com_to_numvertices);+    igraph_vector_destroy(&label_counters);+    igraph_vector_destroy(&dominant_labels);+    igraph_vector_destroy(&nonzero_labels);+    IGRAPH_FINALLY_CLEAN(6);++    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 + 1;+        }+    }++    /* 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_int_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_int_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, NULL));++    /* 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, NULL));++    /* 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, NULL));+    IGRAPH_CHECK(igraph_reindex_membership(&c2, 0, NULL));++    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, NULL));+    IGRAPH_CHECK(igraph_reindex_membership(&c2, 0, NULL));++    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;+}
+ igraph/src/community_leiden.c view
@@ -0,0 +1,1079 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_community.h"+#include "igraph_dqueue.h"+#include "igraph_interface.h"+#include "igraph_interrupt_internal.h"+#include "igraph_memory.h"+#include "igraph_random.h"+#include "igraph_stack.h"+#include "igraph_constructors.h"++/* Move nodes in order to improve the quality of a partition.+ *+ * This function considers each node and greedily moves it to a neighboring+ * community that maximizes the improvement in the quality of a partition.+ *+ * The nodes are examined in a queue, and initially all nodes are put in the+ * queue in a random order. Nodes are popped from the queue when they are+ * examined, and only neighbors of nodes that are moved (which are not part of+ * the cluster the node was moved to) are pushed to the queue again.+ *+ * The \c membership vector is used as the starting point to move around nodes,+ * and is updated in-place.+ *+ */+int igraph_i_community_leiden_fastmovenodes(const igraph_t *graph,+        const igraph_inclist_t *edges_per_node,+        const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,+        const igraph_real_t resolution_parameter,+        igraph_integer_t *nb_clusters,+        igraph_vector_t *membership) {++    igraph_dqueue_t unstable_nodes;+    igraph_real_t max_diff = 0.0, diff = 0.0;+    igraph_integer_t n = igraph_vcount(graph);+    igraph_vector_bool_t neighbor_cluster_added, node_is_stable;+    igraph_vector_t node_order, cluster_weights, edge_weights_per_cluster, neighbor_clusters;+    igraph_vector_int_t nb_nodes_per_cluster;+    igraph_stack_t empty_clusters;+    long int i, j, c, nb_neigh_clusters;++    /* Initialize queue of unstable nodes and whether node is stable. Only+     * unstable nodes are in the queue. */+    IGRAPH_CHECK(igraph_vector_bool_init(&node_is_stable, n));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &node_is_stable);++    IGRAPH_CHECK(igraph_dqueue_init(&unstable_nodes, n));+    IGRAPH_FINALLY(igraph_dqueue_destroy, &unstable_nodes);++    /* Shuffle nodes */+    IGRAPH_CHECK(igraph_vector_init_seq(&node_order, 0, n - 1));+    IGRAPH_FINALLY(igraph_vector_destroy, &node_order);+    IGRAPH_CHECK(igraph_vector_shuffle(&node_order));++    /* Add to the queue */+    for (i = 0; i < n; i++) {+        igraph_dqueue_push(&unstable_nodes, (long int)VECTOR(node_order)[i]);+    }++    /* Initialize cluster weights and nb nodes */+    IGRAPH_CHECK(igraph_vector_init(&cluster_weights, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &cluster_weights);+    IGRAPH_CHECK(igraph_vector_int_init(&nb_nodes_per_cluster, n));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &nb_nodes_per_cluster);+    for (i = 0; i < n; i++) {+        c = (long int)VECTOR(*membership)[i];+        VECTOR(cluster_weights)[c] += VECTOR(*node_weights)[i];+        VECTOR(nb_nodes_per_cluster)[c] += 1;+    }++    /* Initialize empty clusters */+    IGRAPH_CHECK(igraph_stack_init(&empty_clusters, n));+    IGRAPH_FINALLY(igraph_stack_destroy, &empty_clusters);+    for (c = 0; c < n; c++)+        if (VECTOR(nb_nodes_per_cluster)[c] == 0) {+            igraph_stack_push(&empty_clusters, c);+        }++    /* Initialize vectors to be used in calculating differences */+    IGRAPH_CHECK(igraph_vector_init(&edge_weights_per_cluster, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &edge_weights_per_cluster);++    /* Initialize neighboring cluster */+    IGRAPH_CHECK(igraph_vector_bool_init(&neighbor_cluster_added, n));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &neighbor_cluster_added);+    IGRAPH_CHECK(igraph_vector_init(&neighbor_clusters, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &neighbor_clusters);++    /* Iterate while the queue is not empty */+    j = 0;+    while (!igraph_dqueue_empty(&unstable_nodes)) {+        long int v = (long int)igraph_dqueue_pop(&unstable_nodes);+        long int best_cluster, current_cluster = VECTOR(*membership)[v];+        long int degree, i;+        igraph_vector_int_t *edges;++        /* Remove node from current cluster */+        VECTOR(cluster_weights)[current_cluster] -= VECTOR(*node_weights)[v];+        VECTOR(nb_nodes_per_cluster)[current_cluster]--;+        if (VECTOR(nb_nodes_per_cluster)[current_cluster] == 0) {+            igraph_stack_push(&empty_clusters, current_cluster);+        }++        /* Find out neighboring clusters */+        c = (long int)igraph_stack_top(&empty_clusters);+        VECTOR(neighbor_clusters)[0] = c;+        VECTOR(neighbor_cluster_added)[c] = 1;+        nb_neigh_clusters = 1;++        /* Determine the edge weight to each neighboring cluster */+        edges = igraph_inclist_get(edges_per_node, v);+        degree = igraph_vector_int_size(edges);+        for (i = 0; i < degree; i++) {+            long int e = VECTOR(*edges)[i];+            long int u = (long int)IGRAPH_OTHER(graph, e, v);+            c = VECTOR(*membership)[u];+            if (!VECTOR(neighbor_cluster_added)[c]) {+                VECTOR(neighbor_cluster_added)[c] = 1;+                VECTOR(neighbor_clusters)[nb_neigh_clusters++] = c;+            }+            VECTOR(edge_weights_per_cluster)[c] += VECTOR(*edge_weights)[e];+        }++        /* Calculate maximum diff */+        best_cluster = current_cluster;+        max_diff = VECTOR(edge_weights_per_cluster)[current_cluster] - VECTOR(*node_weights)[v] * VECTOR(cluster_weights)[current_cluster] * resolution_parameter;+        for (i = 0; i < nb_neigh_clusters; i++) {+            c = VECTOR(neighbor_clusters)[i];+            diff = VECTOR(edge_weights_per_cluster)[c] - VECTOR(*node_weights)[v] * VECTOR(cluster_weights)[c] * resolution_parameter;+            if (diff > max_diff) {+                best_cluster = c;+                max_diff = diff;+            }+            VECTOR(edge_weights_per_cluster)[c] = 0.0;+            VECTOR(neighbor_cluster_added)[c] = 0;+        }++        /* Move node to best cluster */+        VECTOR(cluster_weights)[best_cluster] += VECTOR(*node_weights)[v];+        VECTOR(nb_nodes_per_cluster)[best_cluster]++;+        if (best_cluster == igraph_stack_top(&empty_clusters)) {+            igraph_stack_pop(&empty_clusters);+        }++        /* Mark node as stable */+        VECTOR(node_is_stable)[v] = 1;++        /* Add stable neighbours that are not part of the new cluster to the queue */+        if (best_cluster != current_cluster) {+            VECTOR(*membership)[v] = best_cluster;++            for (i = 0; i < degree; i++) {+                long int e = VECTOR(*edges)[i];+                long int u = (long int)IGRAPH_OTHER(graph, e, v);+                if (VECTOR(node_is_stable)[u] && VECTOR(*membership)[u] != best_cluster) {+                    igraph_dqueue_push(&unstable_nodes, u);+                    VECTOR(node_is_stable)[u] = 0;+                }+            }+        }++        j++;+        if (j > 10000) {+            IGRAPH_ALLOW_INTERRUPTION();+            j = 0;+        }+    }++    IGRAPH_CHECK(igraph_reindex_membership(membership, NULL, nb_clusters));++    igraph_vector_destroy(&neighbor_clusters);+    igraph_vector_bool_destroy(&neighbor_cluster_added);+    igraph_vector_destroy(&edge_weights_per_cluster);+    igraph_stack_destroy(&empty_clusters);+    igraph_vector_int_destroy(&nb_nodes_per_cluster);+    igraph_vector_destroy(&cluster_weights);+    igraph_vector_destroy(&node_order);+    igraph_dqueue_destroy(&unstable_nodes);+    igraph_vector_bool_destroy(&node_is_stable);++    IGRAPH_FINALLY_CLEAN(9);++    return IGRAPH_SUCCESS;+}++/* Clean a refined membership vector.+ *+ * This function examines all nodes in \c node_subset and updates \c+ * refined_membership to ensure that the clusters are numbered consecutively,+ * starting from \c nb_refined_clusters. The \c nb_refined_clusters is also+ * updated itself. If C is the initial \c nb_refined_clusters and C' the+ * resulting \c nb_refined_clusters, then nodes in \c node_subset are numbered+ * C, C + 1, ..., C' - 1.+ */+int igraph_i_community_leiden_clean_refined_membership(const igraph_vector_t* node_subset, igraph_vector_t *refined_membership, igraph_integer_t* nb_refined_clusters) {+    long int i, n = igraph_vector_size(node_subset);+    igraph_vector_t new_cluster;++    IGRAPH_CHECK(igraph_vector_init(&new_cluster, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &new_cluster);++    /* Clean clusters. We will store the new cluster + 1 so that cluster == 0+     * indicates that no membership was assigned yet. */+    *nb_refined_clusters += 1;+    for (i = 0; i < n; i++) {+        long int v = (long int)VECTOR(*node_subset)[i];+        long int c = (long int)VECTOR(*refined_membership)[v];+        if (VECTOR(new_cluster)[c] == 0) {+            VECTOR(new_cluster)[c] = (igraph_real_t)(*nb_refined_clusters);+            *nb_refined_clusters += 1;+        }+    }++    /* Assign new cluster */+    for (i = 0; i < n; i++) {+        long int v = (long int)VECTOR(*node_subset)[i];+        long int c = (long int)VECTOR(*refined_membership)[v];+        VECTOR(*refined_membership)[v] = VECTOR(new_cluster)[c] - 1;+    }+    /* We used the cluster + 1, so correct */+    *nb_refined_clusters -= 1;++    igraph_vector_destroy(&new_cluster);++    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}++/* Merge nodes for a subset of the nodes. This is used to refine a partition.+ *+ * The nodes included in \c node_subset are assumed to be the nodes i for which+ * membership[i] = cluster_subset.+ *+ * All nodes in \c node_subset are initialized to a singleton partition in \c+ * refined_membership. Only singleton clusters can be merged if they are+ * sufficiently well connected to the current subgraph induced by \c+ * node_subset.+ *+ * We only examine each node once. Instead of greedily choosing the maximum+ * possible cluster to merge with, the cluster is chosen randomly among all+ * possibilities that do not decrease the quality of the partition. The+ * probability of choosing a certain cluster is proportional to exp(diff/beta).+ * For beta to 0 this converges to selecting a cluster with the maximum+ * improvement. For beta to infinity this converges to a uniform distribution+ * among all eligible clusters.+ *+ * The \c refined_membership is updated for node in \c node_subset. The number+ * of refined clusters, \c nb_refined_clusters is used to set the actual refined+ * cluster membership and is updated after this routine. Within each cluster+ * (i.e. for a given \c node_subset), the refined membership is initially simply+ * set to 0, ..., n - 1 (for n nodes in \c node_subset). However, for each \c+ * node_subset the refined membership should of course be unique. Hence, after+ * merging, the refined membership starts with \c nb_refined_clusters, which is+ * also updated to ensure that the resulting \c nb_refined_clusters counts all+ * refined clusters that have already been processed. See+ * igraph_i_community_leiden_clean_refined_membership for more information about+ * this aspect.+ */+int igraph_i_community_leiden_mergenodes(const igraph_t *graph,+        const igraph_inclist_t *edges_per_node,+        const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,+        const igraph_vector_t *node_subset,+        const igraph_vector_t *membership,+        const igraph_integer_t cluster_subset,+        const igraph_real_t resolution_parameter,+        const igraph_real_t beta,+        igraph_integer_t *nb_refined_clusters,+        igraph_vector_t *refined_membership) {+    igraph_vector_t node_order;+    igraph_vector_bool_t non_singleton_cluster, neighbor_cluster_added;+    igraph_real_t max_diff, total_cum_trans_diff, diff = 0.0, total_node_weight = 0.0;+    igraph_integer_t n = igraph_vector_size(node_subset);+    igraph_vector_t cluster_weights, cum_trans_diff, edge_weights_per_cluster, external_edge_weight_per_cluster_in_subset, neighbor_clusters;+    igraph_vector_int_t *edges, nb_nodes_per_cluster;+    long int i, j, degree, nb_neigh_clusters;++    /* Initialize cluster weights */+    IGRAPH_CHECK(igraph_vector_init(&cluster_weights, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &cluster_weights);++    /* Initialize number of nodes per cluster */+    IGRAPH_CHECK(igraph_vector_int_init(&nb_nodes_per_cluster, n));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &nb_nodes_per_cluster);++    /* Initialize external edge weight per cluster in subset */+    IGRAPH_CHECK(igraph_vector_init(&external_edge_weight_per_cluster_in_subset, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &external_edge_weight_per_cluster_in_subset);++    /* Initialize administration for a singleton partition */+    for (i = 0; i < n; i++) {+        long int v = (long int)VECTOR(*node_subset)[i];+        VECTOR(*refined_membership)[v] = i;+        VECTOR(cluster_weights)[i] += VECTOR(*node_weights)[v];+        VECTOR(nb_nodes_per_cluster)[i] += 1;+        total_node_weight += VECTOR(*node_weights)[v];++        /* Find out neighboring clusters */+        edges = igraph_inclist_get(edges_per_node, v);+        degree = igraph_vector_int_size(edges);+        for (j = 0; j < degree; j++) {+            long int e = VECTOR(*edges)[j];+            long int u = (long int)IGRAPH_OTHER(graph, e, v);+            if (VECTOR(*membership)[u] == cluster_subset) {+                VECTOR(external_edge_weight_per_cluster_in_subset)[i] += VECTOR(*edge_weights)[e];+            }+        }+    }++    /* Shuffle nodes */+    IGRAPH_CHECK(igraph_vector_copy(&node_order, node_subset));+    IGRAPH_FINALLY(igraph_vector_destroy, &node_order);+    IGRAPH_CHECK(igraph_vector_shuffle(&node_order));++    /* Initialize non singleton clusters */+    IGRAPH_CHECK(igraph_vector_bool_init(&non_singleton_cluster, n));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &non_singleton_cluster);++    /* Initialize vectors to be used in calculating differences */+    IGRAPH_CHECK(igraph_vector_init(&edge_weights_per_cluster, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &edge_weights_per_cluster);++    /* Initialize neighboring cluster */+    IGRAPH_CHECK(igraph_vector_bool_init(&neighbor_cluster_added, n));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &neighbor_cluster_added);+    IGRAPH_CHECK(igraph_vector_init(&neighbor_clusters, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &neighbor_clusters);++    /* Initialize cumulative transformed difference */+    IGRAPH_CHECK(igraph_vector_init(&cum_trans_diff, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &cum_trans_diff);++    RNG_BEGIN();++    for (i = 0; i < n; i++) {+        long int v = (long int)VECTOR(node_order)[i];+        long int chosen_cluster, best_cluster, current_cluster = (long int)VECTOR(*refined_membership)[v];++        if (!VECTOR(non_singleton_cluster)[current_cluster] &&+            (VECTOR(external_edge_weight_per_cluster_in_subset)[current_cluster] >=+             VECTOR(cluster_weights)[current_cluster] * (total_node_weight - VECTOR(cluster_weights)[current_cluster]) * resolution_parameter)) {+            /* Remove node from current cluster, which is then a singleton by+             * definition. */+            VECTOR(cluster_weights)[current_cluster] = 0.0;+            VECTOR(nb_nodes_per_cluster)[current_cluster] = 0;++            /* Find out neighboring clusters */+            edges = igraph_inclist_get(edges_per_node, v);+            degree = igraph_vector_int_size(edges);++            /* Also add current cluster to ensure it can be chosen. */+            VECTOR(neighbor_clusters)[0] = current_cluster;+            VECTOR(neighbor_cluster_added)[current_cluster] = 1;+            nb_neigh_clusters = 1;+            for (j = 0; j < degree; j++) {+                long int e = (long int)VECTOR(*edges)[j];+                long int u = (long int)IGRAPH_OTHER(graph, e, v);+                if (VECTOR(*membership)[u] == cluster_subset) {+                    long int c = VECTOR(*refined_membership)[u];+                    if (!VECTOR(neighbor_cluster_added)[c]) {+                        VECTOR(neighbor_cluster_added)[c] = 1;+                        VECTOR(neighbor_clusters)[nb_neigh_clusters++] = c;+                    }+                    VECTOR(edge_weights_per_cluster)[c] += VECTOR(*edge_weights)[e];+                }+            }++            /* Calculate diffs */+            best_cluster = current_cluster;+            max_diff = 0.0;+            total_cum_trans_diff = 0.0;+            for (j = 0; j < nb_neigh_clusters; j++) {+                long int c = (long int)VECTOR(neighbor_clusters)[j];+                if (VECTOR(external_edge_weight_per_cluster_in_subset)[c] >= VECTOR(cluster_weights)[c] * (total_node_weight - VECTOR(cluster_weights)[c]) * resolution_parameter) {+                    diff = VECTOR(edge_weights_per_cluster)[c] - VECTOR(*node_weights)[v] * VECTOR(cluster_weights)[c] * resolution_parameter;++                    if (diff > max_diff) {+                        best_cluster = c;+                        max_diff = diff;+                    }++                    /* Calculate the transformed difference for sampling */+                    if (diff >= 0) {+                        total_cum_trans_diff += exp(diff / beta);+                    }++                }++                VECTOR(cum_trans_diff)[j] = total_cum_trans_diff;+                VECTOR(edge_weights_per_cluster)[c] = 0.0;+                VECTOR(neighbor_cluster_added)[c] = 0;+            }++            /* Determine the neighboring cluster to which the currently selected node+             * will be moved.+             */+            if (total_cum_trans_diff < IGRAPH_INFINITY) {+                igraph_real_t r = igraph_rng_get_unif(igraph_rng_default(), 0, total_cum_trans_diff);+                long int chosen_idx;+                igraph_i_vector_binsearch_slice(&cum_trans_diff, r, &chosen_idx, 0, nb_neigh_clusters);+                chosen_cluster = VECTOR(neighbor_clusters)[chosen_idx];+            } else {+                chosen_cluster = best_cluster;+            }++            /* Move node to randomly chosen cluster */+            VECTOR(cluster_weights)[chosen_cluster] += VECTOR(*node_weights)[v];+            VECTOR(nb_nodes_per_cluster)[chosen_cluster]++;++            for (j = 0; j < degree; j++) {+                long int e = (long int)VECTOR(*edges)[j];+                long int u = (long int)IGRAPH_OTHER(graph, e, v);+                if (VECTOR(*membership)[u] == cluster_subset) {+                    if (VECTOR(*refined_membership)[u] == chosen_cluster) {+                        VECTOR(external_edge_weight_per_cluster_in_subset)[chosen_cluster] -= VECTOR(*edge_weights)[e];+                    } else {+                        VECTOR(external_edge_weight_per_cluster_in_subset)[chosen_cluster] += VECTOR(*edge_weights)[e];+                    }+                }+            }++            /* Set cluster  */+            if (chosen_cluster != current_cluster) {+                VECTOR(*refined_membership)[v] = chosen_cluster;++                VECTOR(non_singleton_cluster)[chosen_cluster] = 1;+            }+        } /* end if singleton and may be merged */+    }++    RNG_END();++    IGRAPH_CHECK(igraph_i_community_leiden_clean_refined_membership(node_subset, refined_membership, nb_refined_clusters));++    igraph_vector_destroy(&cum_trans_diff);+    igraph_vector_destroy(&neighbor_clusters);+    igraph_vector_bool_destroy(&neighbor_cluster_added);+    igraph_vector_destroy(&edge_weights_per_cluster);+    igraph_vector_bool_destroy(&non_singleton_cluster);+    igraph_vector_destroy(&node_order);+    igraph_vector_destroy(&external_edge_weight_per_cluster_in_subset);+    igraph_vector_int_destroy(&nb_nodes_per_cluster);+    igraph_vector_destroy(&cluster_weights);++    IGRAPH_FINALLY_CLEAN(9);++    return IGRAPH_SUCCESS;+}++/* Create clusters out of a membership vector.+ *+ * The cluster pointer vector should be initialized for all entries of the+ * membership vector, no range checking is performed. If a vector for a cluster+ * does not yet exist it will be created and initialized. If a vector for a+ * cluster already does exist it will not be emptied on first use. Hence, it+ * should be ensured that all clusters are always properly empty (or+ * non-existing) before calling this function.+ */+int igraph_i_community_get_clusters(const igraph_vector_t *membership, igraph_vector_ptr_t *clusters) {+    long int i, c, n = igraph_vector_size(membership);+    igraph_vector_t *cluster;+    for (i = 0; i < n; i++) {+        /* Get cluster for node i */+        c = VECTOR(*membership)[i];+        cluster = (igraph_vector_t*)VECTOR(*clusters)[c];++        /* No cluster vector exists yet, so we create a new one */+        if (!cluster) {+            cluster = igraph_Calloc(1, igraph_vector_t);+            if (cluster == 0) {+                IGRAPH_ERROR("Cannot allocate memory for assigning cluster", IGRAPH_ENOMEM);+            }+            IGRAPH_CHECK(igraph_vector_init(cluster, 0));+            VECTOR(*clusters)[c] = cluster;+        }++        /* Add node i to cluster vector */+        igraph_vector_push_back(cluster, i);+    }++    return IGRAPH_SUCCESS;+}++/* Aggregate the graph based on the \c refined membership while setting the+ * membership of each aggregated node according to the \c membership.+ *+ * Technically speaking we have that+ * aggregated_membership[refined_membership[v]] = membership[v] for each node v.+ *+ * The new aggregated graph is returned in \c aggregated_graph. This graph+ * object should not yet be initialized, `igraph_create` is called on it, and+ * responsibility for destroying the object lies with the calling method+ *+ * The remaining results, aggregated_edge_weights, aggregate_node_weights and+ * aggregated_membership are all expected to be initialized.+ *+ */+int igraph_i_community_leiden_aggregate(+    const igraph_t *graph, const igraph_inclist_t *edges_per_node, const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,+    const igraph_vector_t *membership, const igraph_vector_t *refined_membership, const igraph_integer_t nb_refined_clusters,+    igraph_t *aggregated_graph, igraph_vector_t *aggregated_edge_weights, igraph_vector_t *aggregated_node_weights, igraph_vector_t *aggregated_membership) {+    igraph_vector_t aggregated_edges, edge_weight_to_cluster;+    igraph_vector_ptr_t refined_clusters;+    igraph_vector_int_t *incident_edges;+    igraph_vector_t neighbor_clusters;+    igraph_vector_bool_t neighbor_cluster_added;+    long int i, j, c, degree, nb_neigh_clusters;++    /* Get refined clusters */+    IGRAPH_CHECK(igraph_vector_ptr_init(&refined_clusters, nb_refined_clusters));+    igraph_vector_ptr_set_item_destructor(&refined_clusters, igraph_vector_destroy);+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &refined_clusters);+    IGRAPH_CHECK(igraph_i_community_get_clusters(refined_membership, &refined_clusters));++    /* Initialize new edges */+    IGRAPH_CHECK(igraph_vector_init(&aggregated_edges, 0));+    IGRAPH_FINALLY(igraph_vector_destroy, &aggregated_edges);++    /* We clear the aggregated edge weights, we will push each new edge weight */+    igraph_vector_clear(aggregated_edge_weights);+    /* Simply resize the aggregated node weights and membership, they can be set+     * directly */+    IGRAPH_CHECK(igraph_vector_resize(aggregated_node_weights, nb_refined_clusters));+    IGRAPH_CHECK(igraph_vector_resize(aggregated_membership, nb_refined_clusters));++    IGRAPH_CHECK(igraph_vector_init(&edge_weight_to_cluster, nb_refined_clusters));+    IGRAPH_FINALLY(igraph_vector_destroy, &edge_weight_to_cluster);++    /* Initialize neighboring cluster */+    IGRAPH_CHECK(igraph_vector_bool_init(&neighbor_cluster_added, nb_refined_clusters));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &neighbor_cluster_added);+    IGRAPH_CHECK(igraph_vector_init(&neighbor_clusters, nb_refined_clusters));+    IGRAPH_FINALLY(igraph_vector_destroy, &neighbor_clusters);++    /* Check per cluster */+    for (c = 0; c < nb_refined_clusters; c++) {+        igraph_vector_t* refined_cluster = (igraph_vector_t*)VECTOR(refined_clusters)[c];+        long int n_c = igraph_vector_size(refined_cluster);+        long int v = -1;++        /* Calculate the total edge weight to other clusters */+        VECTOR(*aggregated_node_weights)[c] = 0.0;+        nb_neigh_clusters = 0;+        for (i = 0; i < n_c; i++) {+            v = (long int)VECTOR(*refined_cluster)[i];+            incident_edges = igraph_inclist_get(edges_per_node, v);+            degree = igraph_vector_int_size(incident_edges);++            for (j = 0; j < degree; j++) {+                long int e = VECTOR(*incident_edges)[j];+                long int u = (long int)IGRAPH_OTHER(graph, e, v);+                long int c2 = VECTOR(*refined_membership)[u];++                if (c2 > c) {+                    if (!VECTOR(neighbor_cluster_added)[c2]) {+                        VECTOR(neighbor_cluster_added)[c2] = 1;+                        VECTOR(neighbor_clusters)[nb_neigh_clusters++] = c2;+                    }+                    VECTOR(edge_weight_to_cluster)[c2] += VECTOR(*edge_weights)[e];+                }+            }++            VECTOR(*aggregated_node_weights)[c] += VECTOR(*node_weights)[v];+        }++        /* Add actual edges from this cluster to the other clusters */+        for (i = 0; i < nb_neigh_clusters; i++) {+            long int c2 = VECTOR(neighbor_clusters)[i];++            /* Add edge */+            igraph_vector_push_back(&aggregated_edges, c); igraph_vector_push_back(&aggregated_edges, c2);++            /* Add edge weight */+            igraph_vector_push_back(aggregated_edge_weights, VECTOR(edge_weight_to_cluster)[c2]);++            VECTOR(edge_weight_to_cluster)[c2] = 0.0;+            VECTOR(neighbor_cluster_added)[c2] = 0;+        }++        VECTOR(*aggregated_membership)[c] = VECTOR(*membership)[v];++    }++    IGRAPH_CHECK(igraph_create(aggregated_graph, &aggregated_edges, nb_refined_clusters,+                               IGRAPH_UNDIRECTED));++    igraph_vector_destroy(&neighbor_clusters);+    igraph_vector_bool_destroy(&neighbor_cluster_added);+    igraph_vector_destroy(&edge_weight_to_cluster);+    igraph_vector_destroy(&aggregated_edges);+    igraph_vector_ptr_destroy_all(&refined_clusters);++    IGRAPH_FINALLY_CLEAN(5);++    return IGRAPH_SUCCESS;+}++/* Calculate the quality of the partition.+ *+ * The quality is defined as+ *+ * 1 / 2m sum_ij (A_ij - gamma n_i n_j)d(s_i, s_j)+ *+ * where m is the total edge weight, A_ij is the weight of edge (i, j), gamma is+ * the so-called resolution parameter, n_i is the node weight of node i, s_i is+ * the cluster of node i and d(x, y) = 1 if and only if x = y and 0 otherwise.+ *+ * Note that by setting n_i = k_i the degree of node i and dividing gamma by 2m,+ * we effectively optimize modularity. By setting n_i = 1 we optimize the+ * Constant Potts Model.+ *+ * This can be represented as a sum over clusters as+ *+ * 1 / 2m sum_c (e_c - gamma N_c^2)+ *+ * where e_c = sum_ij A_ij d(s_i, c)d(s_j, c) is (twice) the internal edge+ * weight in cluster c and N_c = sum_i n_i d(s_i, c) is the sum of the node+ * weights inside cluster c. This is how the quality is calculated in practice.+ *+ */+int igraph_i_community_leiden_quality(const igraph_t *graph, const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,+                                      const igraph_vector_t *membership, const igraph_integer_t nb_comms, const igraph_real_t resolution_parameter,+                                      igraph_real_t *quality) {+    igraph_vector_t cluster_weights;+    igraph_real_t total_edge_weight = 0.0;+    igraph_eit_t eit;+    long int i, c, n = igraph_vcount(graph);;++    *quality = 0.0;++    /* Create the edgelist */+    IGRAPH_CHECK(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 e = IGRAPH_EIT_GET(eit), from, to;+        IGRAPH_CHECK(igraph_edge(graph, e, &from, &to));+        total_edge_weight += VECTOR(*edge_weights)[e];+        /* We add the internal edge weights */+        if (VECTOR(*membership)[(long int) from] == VECTOR(*membership)[(long int) to]) {+            *quality += 2 * VECTOR(*edge_weights)[e];+        }+        IGRAPH_EIT_NEXT(eit);+    }+    igraph_eit_destroy(&eit);+    IGRAPH_FINALLY_CLEAN(1);++    /* Initialize cluster weights and nb nodes */+    IGRAPH_CHECK(igraph_vector_init(&cluster_weights, n));+    IGRAPH_FINALLY(igraph_vector_destroy, &cluster_weights);+    for (i = 0; i < n; i++) {+        c = VECTOR(*membership)[i];+        VECTOR(cluster_weights)[c] += VECTOR(*node_weights)[i];+    }++    /* We subtract gamma * N_c^2 */+    for (c = 0; c < nb_comms; c++) {+        *quality -= resolution_parameter * VECTOR(cluster_weights)[c] * VECTOR(cluster_weights)[c];+    }++    igraph_vector_destroy(&cluster_weights);+    IGRAPH_FINALLY_CLEAN(1);++    /* We normalise by 2m */+    *quality /= (2.0 * total_edge_weight);++    return IGRAPH_SUCCESS;+}++/* This is the core of the Leiden algorithm and relies on subroutines to+ * perform the three different phases: (1) local moving of nodes, (2)+ * refinement of the partition and (3) aggregation of the network based on the+ * refined partition, using the non-refined partition to create an initial+ * partition for the aggregate network.+ */+int igraph_i_community_leiden(const igraph_t *graph,+                              const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,+                              const igraph_real_t resolution_parameter, const igraph_real_t beta,+                              igraph_vector_t *membership, igraph_integer_t *nb_clusters, igraph_real_t *quality) {+    igraph_integer_t nb_refined_clusters;+    long int i, c, n = igraph_vcount(graph);+    igraph_t *aggregated_graph, *tmp_graph;+    igraph_vector_t *aggregated_edge_weights, *aggregated_node_weights, *aggregated_membership;+    igraph_vector_t tmp_edge_weights, tmp_node_weights, tmp_membership;+    igraph_vector_t refined_membership;+    igraph_vector_int_t aggregate_node;+    igraph_vector_ptr_t clusters;+    igraph_inclist_t edges_per_node;+    igraph_bool_t continue_clustering;+    igraph_integer_t level = 0;++    /* Initialize temporary weights and membership to be used in aggregation */+    IGRAPH_CHECK(igraph_vector_init(&tmp_edge_weights, 0));+    IGRAPH_FINALLY(igraph_vector_destroy, &tmp_edge_weights);+    IGRAPH_CHECK(igraph_vector_init(&tmp_node_weights, 0));+    IGRAPH_FINALLY(igraph_vector_destroy, &tmp_node_weights);+    IGRAPH_CHECK(igraph_vector_init(&tmp_membership, 0));+    IGRAPH_FINALLY(igraph_vector_destroy, &tmp_membership);++    /* Initialize clusters */+    IGRAPH_CHECK(igraph_vector_ptr_init(&clusters, n));+    igraph_vector_ptr_set_item_destructor(&clusters, igraph_vector_destroy);+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &clusters);+    /* Initialize aggregate nodes, which initially is identical to simply the+     * nodes in the graph. */+    IGRAPH_CHECK(igraph_vector_int_init(&aggregate_node, n));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &aggregate_node);+    for (i = 0; i < n; i++) {+        VECTOR(aggregate_node)[i] = i;+    }++    IGRAPH_CHECK(igraph_vector_init(&refined_membership, 0));+    IGRAPH_FINALLY(igraph_vector_destroy, &refined_membership);++    /* Initialize aggregated graph, weights and membership. */+    aggregated_graph = graph;+    aggregated_edge_weights = edge_weights;+    aggregated_node_weights = node_weights;+    aggregated_membership = membership;++    /* Clean membership and count number of *clusters */+    IGRAPH_CHECK(igraph_reindex_membership(aggregated_membership, NULL, nb_clusters));++    if (*nb_clusters > n) {+        IGRAPH_ERROR("Too many communities in membership vector", IGRAPH_EINVAL);+    }++    do {++        /* Get incidence list for fast iteration */+        IGRAPH_CHECK(igraph_inclist_init(aggregated_graph, &edges_per_node, IGRAPH_ALL));+        IGRAPH_FINALLY(igraph_inclist_destroy, &edges_per_node);++        /* Move around the nodes in order to increase the quality */+        IGRAPH_CHECK(igraph_i_community_leiden_fastmovenodes(aggregated_graph,+                     &edges_per_node,+                     aggregated_edge_weights, aggregated_node_weights,+                     resolution_parameter,+                     nb_clusters,+                     aggregated_membership));++        /* We only continue clustering if not all clusters are represented by a+         * single node yet+         */+        continue_clustering = (*nb_clusters < igraph_vcount(aggregated_graph));++        if (continue_clustering) {+            /* Set original membership */+            if (level > 0) {+                for (i = 0; i < n; i++) {+                    long int v_aggregate = VECTOR(aggregate_node)[i];+                    VECTOR(*membership)[i] = VECTOR(*aggregated_membership)[v_aggregate];+                }+            }++            /* Get node sets for each cluster. */+            IGRAPH_CHECK(igraph_i_community_get_clusters(aggregated_membership, &clusters));++            /* Ensure refined membership is correct size */+            IGRAPH_CHECK(igraph_vector_resize(&refined_membership, igraph_vcount(aggregated_graph)));++            /* Refine each cluster */+            nb_refined_clusters = 0;+            for (c = 0; c < *nb_clusters; c++) {+                igraph_vector_t* cluster = (igraph_vector_t*)VECTOR(clusters)[c];+                IGRAPH_CHECK(igraph_i_community_leiden_mergenodes(aggregated_graph,+                             &edges_per_node,+                             aggregated_edge_weights, aggregated_node_weights,+                             cluster, aggregated_membership, c,+                             resolution_parameter, beta,+                             &nb_refined_clusters, &refined_membership));+                /* Empty cluster */+                igraph_vector_clear(cluster);+            }++            /* If refinement didn't aggregate anything, we aggregate on the basis of+             * the actual clustering */+            if (nb_refined_clusters >= igraph_vcount(aggregated_graph)) {+                igraph_vector_update(&refined_membership, aggregated_membership);+            }++            /* Keep track of aggregate node. */+            for (i = 0; i < n; i++) {+                /* Current aggregate node */+                igraph_integer_t v_aggregate = VECTOR(aggregate_node)[i];+                /* New aggregate node */+                VECTOR(aggregate_node)[i] = (igraph_integer_t)VECTOR(refined_membership)[v_aggregate];+            }++            /* Allocate temporary graph */+            tmp_graph = igraph_Calloc(1, igraph_t);+            if (tmp_graph == 0) {+                IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate graph", IGRAPH_ENOMEM);+            }+            IGRAPH_FINALLY(free, tmp_graph);++            IGRAPH_CHECK(igraph_i_community_leiden_aggregate(+                             aggregated_graph, &edges_per_node, aggregated_edge_weights, aggregated_node_weights,+                             aggregated_membership, &refined_membership, nb_refined_clusters,+                             tmp_graph, &tmp_edge_weights, &tmp_node_weights, &tmp_membership));++            /* Graph has been created by aggregation, ensure it is properly destroyed if+             * an error occurs. */+            IGRAPH_FINALLY(igraph_destroy, tmp_graph);++            if (level >= 1) {+                /* Destroy previously allocated graph (note that aggregated_graph points to+                 * the previously allocated tmp_graph). */+                igraph_destroy(aggregated_graph);+                igraph_Free(aggregated_graph);+                IGRAPH_FINALLY_CLEAN(2);+            }++            /* On the lowest level, the actual graph and node and edge weights and+             * membership are used. On higher levels, we will have to use a new graph+             * and node and edge weights to represent them. We perform the allocation+             * of memory here. We only allocate the memory once, and simply update+             * them in any subsequent rounds.+             */+            if (level == 0) {+                aggregated_edge_weights = igraph_Calloc(1, igraph_vector_t);+                if (aggregated_edge_weights == 0) {+                    IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate edge weights", IGRAPH_ENOMEM);+                }+                IGRAPH_FINALLY(free, aggregated_edge_weights);+                IGRAPH_CHECK(igraph_vector_init(aggregated_edge_weights, 0));+                IGRAPH_FINALLY(igraph_vector_destroy, aggregated_edge_weights);++                aggregated_node_weights = igraph_Calloc(1, igraph_vector_t);+                if (aggregated_node_weights == 0) {+                    IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate node weights", IGRAPH_ENOMEM);+                }+                IGRAPH_FINALLY(free, aggregated_node_weights);+                IGRAPH_CHECK(igraph_vector_init(aggregated_node_weights, 0));+                IGRAPH_FINALLY(igraph_vector_destroy, aggregated_node_weights);++                aggregated_membership = igraph_Calloc(1, igraph_vector_t);+                if (aggregated_membership == 0) {+                    IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for aggregate membership", IGRAPH_ENOMEM);+                }+                IGRAPH_FINALLY(free, aggregated_membership);+                IGRAPH_CHECK(igraph_vector_init(aggregated_membership, 0));+                IGRAPH_FINALLY(igraph_vector_destroy, aggregated_membership);+            }++            /* Set the aggregated graph correctly */+            aggregated_graph = tmp_graph;++            /* Update the aggregated administration. This does not allocate memory,+             * it will always fit in existing memory allocated previously. */+            igraph_vector_update(aggregated_edge_weights, &tmp_edge_weights);+            igraph_vector_update(aggregated_node_weights, &tmp_node_weights);+            igraph_vector_update(aggregated_membership, &tmp_membership);++            level += 1;+        }++        /* We are done iterating, so we destroy the incidence list */+        igraph_inclist_destroy(&edges_per_node);+        IGRAPH_FINALLY_CLEAN(1);+    } while (continue_clustering);++    /* If memory was allocated to represent the aggregated administration we need+     * to make sure it is properly freed. This is only done if we have at least+     * passed on to the next level of aggregation.+     */+    if (level > 0) {+        igraph_destroy(aggregated_graph);+        igraph_Free(aggregated_graph);+        igraph_vector_destroy(aggregated_membership);+        igraph_Free(aggregated_membership);+        igraph_vector_destroy(aggregated_node_weights);+        igraph_Free(aggregated_node_weights);+        igraph_vector_destroy(aggregated_edge_weights);+        igraph_Free(aggregated_edge_weights);+        IGRAPH_FINALLY_CLEAN(8);+    }++    /* Free remaining memory */+    igraph_vector_destroy(&refined_membership);+    igraph_vector_int_destroy(&aggregate_node);+    igraph_vector_ptr_destroy_all(&clusters);+    igraph_vector_destroy(&tmp_membership);+    igraph_vector_destroy(&tmp_node_weights);+    igraph_vector_destroy(&tmp_edge_weights);+    IGRAPH_FINALLY_CLEAN(6);++    /* Calculate quality */+    if (quality) {+        igraph_i_community_leiden_quality(graph, edge_weights, node_weights, membership, *nb_clusters, resolution_parameter, quality);+    }++    return IGRAPH_SUCCESS;+}++/**+ * \ingroup communities+ * \function igraph_community_leiden+ * \brief Finding community structure using the Leiden algorithm.+ *+ * This function implements the Leiden algorithm for finding community+ * structure, see Traag, V. A., Waltman, L., &amp; van Eck, N. J. (2019). From+ * Louvain to Leiden: guaranteeing well-connected communities. Scientific+ * reports, 9(1), 5233.  http://dx.doi.org/10.1038/s41598-019-41695-z.+ *+ * </para><para>+ * It is similar to the multilevel algorithm, often called the Louvain+ * algorithm, but it is faster and yields higher quality solutions. It can+ * optimize both modularity and the Constant Potts Model, which does not suffer+ * from the resolution-limit (see preprint http://arxiv.org/abs/1104.3083).+ *+ * </para><para>+ * The Leiden algorithm consists of three phases: (1) local moving of nodes,+ * (2) refinement of the partition and (3) aggregation of the network based on+ * the refined partition, using the non-refined partition to create an initial+ * partition for the aggregate network. In the local move procedure in the+ * Leiden algorithm, only nodes whose neighborhood has changed are visited. The+ * refinement is done by restarting from a singleton partition within each+ * cluster and gradually merging the subclusters. When aggregating, a single+ * cluster may then be represented by several nodes (which are the subclusters+ * identified in the refinement).+ *+ * </para><para>+ * The Leiden algorithm provides several guarantees. The Leiden algorithm is+ * typically iterated: the output of one iteration is used as the input for the+ * next iteration. At each iteration all clusters are guaranteed to be+ * connected and well-separated. After an iteration in which nothing has+ * changed, all nodes and some parts are guaranteed to be locally optimally+ * assigned. Finally, asymptotically, all subsets of all clusters are+ * guaranteed to be locally optimally assigned. For more details, please see+ * Traag, Waltman &amp; van Eck (2019).+ *+ * </para><para>+ * The objective function being optimized is+ *+ * </para><para>+ * 1 / 2m sum_ij (A_ij - gamma n_i n_j)d(s_i, s_j)+ *+ * </para><para>+ * where m is the total edge weight, A_ij is the weight of edge (i, j), gamma is+ * the so-called resolution parameter, n_i is the node weight of node i, s_i is+ * the cluster of node i and d(x, y) = 1 if and only if x = y and 0 otherwise.+ * By setting n_i = k_i, the degree of node i, and dividing gamma by 2m, you+ * effectively obtain an expression for modularity. Hence, the standard+ * modularity will be optimized when you supply the degrees as \c node_weights+ * and by supplying as a resolution parameter 1.0/(2*m), with m the number of+ * edges.+ *+ * \param graph The input graph. It must be an undirected graph.+ * \param edge_weights Numeric vector containing edge weights. If \c NULL, every edge+ *    has equal weight of 1. The weights need not be non-negative.+ * \param node_weights Numeric vector containing node weights.+ * \param resolution_parameter The resolution parameter used, which is+ *    represented by gamma in the objective function mentioned in the+ *    documentation.+ * \param beta The randomness used in the refinement step when merging. A small+ *    amount of randomness (\c beta = 0.01) typically works well.+ * \param start Start from membership vector. If this is true, the optimization+ *    will start from the provided membership vector. If this is false, the+ *    optimization will start from a singleton partition.+ * \param membership The membership vector. This is both used as the initial+ *    membership from which optimisation starts and is updated in place. It+ *    must hence be properly initialized. When finding clusters from scratch it+ *    is typically started using a singleton clustering. This can be achieved+ *    using \c igraph_vector_init_seq.+ * \param nb_clusters The number of clusters contained in \c membership. Must+ *    not be a \c NULL pointer.+ * \param quality The quality of the partition, in terms of the objective+ *    function as included in the documentation. If \c NULL the quality will+ *    not be calculated.+ * \return Error code.+ *+ * Time complexity: near linear on sparse graphs.+ *+ * \example examples/simple/igraph_community_leiden.c+ */+int igraph_community_leiden(const igraph_t *graph,+                            const igraph_vector_t *edge_weights, const igraph_vector_t *node_weights,+                            const igraph_real_t resolution_parameter, const igraph_real_t beta, const igraph_bool_t start,+                            igraph_vector_t *membership, igraph_integer_t *nb_clusters, igraph_real_t *quality) {+    igraph_vector_t *i_edge_weights, *i_node_weights;+    int ret;+    igraph_integer_t n = igraph_vcount(graph);++    if (start) {+        if (!membership) {+            IGRAPH_ERROR("Cannot start optimization if membership is missing", IGRAPH_EINVAL);+        }++        if (igraph_vector_size(membership) != n) {+            IGRAPH_ERROR("Initial membership length does not equal the number of vertices", IGRAPH_EINVAL);+        }+    } else {+        int i;+        if (!membership)+            IGRAPH_ERROR("Membership vector should be supplied and initialized, "+                         "even when not starting optimization from it", IGRAPH_EINVAL);++        igraph_vector_resize(membership, n);+        for (i = 0; i < n; i++) {+            VECTOR(*membership)[i] = i;+        }+    }+++    if (igraph_is_directed(graph)) {+        IGRAPH_ERROR("Leiden algorithm is only implemented for undirected graphs", IGRAPH_EINVAL);+    }++    /* Check edge weights to possibly use default */+    if (!edge_weights) {+        i_edge_weights = igraph_Calloc(1, igraph_vector_t);+        if (i_edge_weights == 0) {+            IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for edge weights", IGRAPH_ENOMEM);+        }+        IGRAPH_CHECK(igraph_vector_init(i_edge_weights, igraph_ecount(graph)));+        IGRAPH_FINALLY(free, i_edge_weights);+        IGRAPH_FINALLY(igraph_vector_destroy, i_edge_weights);+        igraph_vector_fill(i_edge_weights, 1);+    } else {+        i_edge_weights = edge_weights;+    }++    /* Check edge weights to possibly use default */+    if (!node_weights) {+        i_node_weights = igraph_Calloc(1, igraph_vector_t);+        if (i_node_weights == 0) {+            IGRAPH_ERROR("Leiden algorithm failed, could not allocate memory for node weights", IGRAPH_ENOMEM);+        }+        IGRAPH_CHECK(igraph_vector_init(i_node_weights, n));+        IGRAPH_FINALLY(free, i_node_weights);+        IGRAPH_FINALLY(igraph_vector_destroy, i_node_weights);+        igraph_vector_fill(i_node_weights, 1);+    } else {+        i_node_weights = node_weights;+    }++    /* Perform actual Leiden algorithm */+    ret = igraph_i_community_leiden(graph, i_edge_weights, i_node_weights,+                                    resolution_parameter, beta,+                                    membership, nb_clusters, quality);++    if (!edge_weights) {+        igraph_vector_destroy(i_edge_weights);+        igraph_Free(i_edge_weights);+        IGRAPH_FINALLY_CLEAN(2);+    }++    if (!node_weights) {+        igraph_vector_destroy(i_node_weights);+        igraph_Free(i_node_weights);+        IGRAPH_FINALLY_CLEAN(2);+    }++    return ret;+}
+ igraph/src/complex.c view
@@ -0,0 +1,392 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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));+}+
+ igraph/src/components.c view
@@ -0,0 +1,1248 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_progress.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>++static int igraph_i_clusters_weak(const igraph_t *graph, igraph_vector_t *membership,+                                  igraph_vector_t *csize, igraph_integer_t *no);++static int igraph_i_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_i_clusters_weak(graph, membership, csize, no);+    } else if (mode == IGRAPH_STRONG) {+        return igraph_i_clusters_strong(graph, membership, csize, no);+    } else {+        IGRAPH_ERROR("Cannot calculate clusters", IGRAPH_EINVAL);+    }++    return 1;+}++static int igraph_i_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;+}++static int igraph_i_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, n, num_seen;+    igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;++    long int no_of_clusters = 1;+    long int act_cluster_size;++    igraph_vector_t out = IGRAPH_VECTOR_NULL;+    const igraph_vector_int_t* tmp;++    igraph_adjlist_t adjlist;++    /* The result */++    IGRAPH_VECTOR_INIT_FINALLY(&next_nei, no_of_nodes);+    IGRAPH_VECTOR_INIT_FINALLY(&out, 0);+    IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);++    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);+    }++    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_OUT));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);++    num_seen = 0;+    for (i = 0; i < no_of_nodes; i++) {+        IGRAPH_ALLOW_INTERRUPTION();++        tmp = igraph_adjlist_get(&adjlist, i);+        if (VECTOR(next_nei)[i] > igraph_vector_int_size(tmp)) {+            continue;+        }++        IGRAPH_CHECK(igraph_dqueue_push(&q, i));+        while (!igraph_dqueue_empty(&q)) {+            long int act_node = (long int) igraph_dqueue_back(&q);+            tmp = igraph_adjlist_get(&adjlist, act_node);+            if (VECTOR(next_nei)[act_node] == 0) {+                /* this is the first time we've met this vertex */+                VECTOR(next_nei)[act_node]++;+            } else if (VECTOR(next_nei)[act_node] <= igraph_vector_int_size(tmp)) {+                /* we've already met this vertex but it has more children */+                long int neighbor = (long int) VECTOR(*tmp)[(long int)+                                    VECTOR(next_nei)[act_node] - 1];+                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);+                num_seen++;++                if (num_seen % 10000 == 0) {+                    /* time to report progress and allow the user to interrupt */+                    IGRAPH_PROGRESS("Strongly connected components: ",+                                    num_seen * 50.0 / no_of_nodes, NULL);+                    IGRAPH_ALLOW_INTERRUPTION();+                }+            }+        } /* while q */+    }  /* for */++    IGRAPH_PROGRESS("Strongly connected components: ", 50.0, NULL);++    igraph_adjlist_destroy(&adjlist);+    IGRAPH_FINALLY_CLEAN(1);++    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);++    /* OK, we've the 'out' values for the nodes, let's use them in+       decreasing order with the help of a heap */++    igraph_vector_null(&next_nei);             /* mark already added vertices */+    num_seen = 0;++    while (!igraph_vector_empty(&out)) {+        long int grandfather = (long int) igraph_vector_pop_back(&out);++        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));++        num_seen++;+        if (num_seen % 10000 == 0) {+            /* time to report progress and allow the user to interrupt */+            IGRAPH_PROGRESS("Strongly connected components: ",+                            50.0 + num_seen * 50.0 / no_of_nodes, NULL);+            IGRAPH_ALLOW_INTERRUPTION();+        }++        while (!igraph_dqueue_empty(&q)) {+            long int act_node = (long int) igraph_dqueue_pop_back(&q);+            tmp = igraph_adjlist_get(&adjlist, act_node);+            n = igraph_vector_int_size(tmp);+            for (i = 0; i < n; i++) {+                long int neighbor = (long int) VECTOR(*tmp)[i];+                if (VECTOR(next_nei)[neighbor] != 0) {+                    continue;+                }+                IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));+                VECTOR(next_nei)[neighbor] = 1;+                act_cluster_size++;+                if (membership) {+                    VECTOR(*membership)[neighbor] = no_of_clusters - 1;+                }++                num_seen++;+                if (num_seen % 10000 == 0) {+                    /* time to report progress and allow the user to interrupt */+                    IGRAPH_PROGRESS("Strongly connected components: ",+                                    50.0 + num_seen * 50.0 / no_of_nodes, NULL);+                    IGRAPH_ALLOW_INTERRUPTION();+                }+            }+        }++        no_of_clusters++;+        if (csize) {+            IGRAPH_CHECK(igraph_vector_push_back(csize, act_cluster_size));+        }+    }++    IGRAPH_PROGRESS("Strongly connected components: ", 100.0, NULL);++    if (no) {+        *no = (igraph_integer_t) no_of_clusters - 1;+    }++    /* Clean up, return */++    igraph_adjlist_destroy(&adjlist);+    igraph_vector_destroy(&out);+    igraph_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_i_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]);+        }+    }+}++static int igraph_i_decompose_weak(const igraph_t *graph,+                                   igraph_vector_ptr_t *components,+                                   long int maxcompno, long int minelements);++static int igraph_i_decompose_strong(const igraph_t *graph,+                                     igraph_vector_ptr_t *components,+                                     long int maxcompno, long int minelements);++/**+ * \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.+ * \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) {+    if (mode == IGRAPH_WEAK || !igraph_is_directed(graph)) {+        return igraph_i_decompose_weak(graph, components, maxcompno, minelements);+    } else if (mode == IGRAPH_STRONG) {+        return igraph_i_decompose_strong(graph, components, maxcompno, minelements);+    } else {+        IGRAPH_ERROR("Cannot decompose graph", IGRAPH_EINVAL);+    }++    return 1;+}++static int igraph_i_decompose_weak(const igraph_t *graph,+                                   igraph_vector_ptr_t *components,+                                   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 (maxcompno < 0) {+        maxcompno = LONG_MAX;+    }++    igraph_vector_ptr_clear(components);+    IGRAPH_FINALLY(igraph_decompose_destroy, components);++    /* already_added keeps track of what nodes made it into a graph already */+    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);++    /* add a node and its neighbors at once, recursively+       then switch to next node that has not been added already */+    for (actstart = 0; resco < maxcompno && actstart < no_of_nodes; actstart++) {++        if (already_added[actstart]) {+            continue;+        }+        IGRAPH_ALLOW_INTERRUPTION();++        igraph_vector_clear(&verts);++        /* add the node itself */+        already_added[actstart] = 1;+        IGRAPH_CHECK(igraph_vector_push_back(&verts, actstart));+        IGRAPH_CHECK(igraph_dqueue_push(&q, actstart));++        /* add the neighbors, recursively */+        while (!igraph_dqueue_empty(&q) ) {+            /* pop from the queue of this component */+            long int actvert = (long int) igraph_dqueue_pop(&q);+            IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) actvert,+                                          IGRAPH_ALL));+            /* iterate over the neighbors */+            for (i = 0; i < igraph_vector_size(&neis); i++) {+                long int neighbor = (long int) VECTOR(neis)[i];+                if (already_added[neighbor] == 1) {+                    continue;+                }+                /* add neighbor */+                already_added[neighbor] = 1;++                /* recursion: append neighbor to the queues */+                IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));+                IGRAPH_CHECK(igraph_vector_push_back(&verts, neighbor));+            }+        }++        /* 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;+}++static int igraph_i_decompose_strong(const igraph_t *graph,+                                     igraph_vector_ptr_t *components,+                                     long int maxcompno, long int minelements) {+++    long int no_of_nodes = igraph_vcount(graph);++    /* this is a heap used twice for checking what nodes have+     * been counted already */+    igraph_vector_t next_nei = IGRAPH_VECTOR_NULL;++    long int i, n, num_seen;+    igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;++    long int no_of_clusters = 1;+    long int act_cluster_size;++    igraph_vector_t out = IGRAPH_VECTOR_NULL;+    const igraph_vector_int_t* tmp;++    igraph_adjlist_t adjlist;+    igraph_vector_t verts;+    igraph_t *newg;++    igraph_vector_ptr_clear(components);+    IGRAPH_FINALLY(igraph_decompose_destroy, components);++    /* The result */++    IGRAPH_VECTOR_INIT_FINALLY(&verts, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&next_nei, no_of_nodes);+    IGRAPH_VECTOR_INIT_FINALLY(&out, 0);+    IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);++    IGRAPH_CHECK(igraph_vector_reserve(&out, no_of_nodes));++    igraph_vector_null(&out);++    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_OUT));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);++    /* number of components seen */+    num_seen = 0;+    /* populate the 'out' vector by browsing a node and following up+       all its neighbors recursively, then switching to the next+       unassigned node */+    for (i = 0; i < no_of_nodes; i++) {+        IGRAPH_ALLOW_INTERRUPTION();++        /* get all the 'out' neighbors of this node+         * NOTE: next_nei is initialized [0, 0, ...] */+        tmp = igraph_adjlist_get(&adjlist, i);+        if (VECTOR(next_nei)[i] > igraph_vector_int_size(tmp)) {+            continue;+        }++        /* add this node to the queue for this component */+        IGRAPH_CHECK(igraph_dqueue_push(&q, i));++        /* consume the tree from this node ("root") recursively+         * until there is no more */+        while (!igraph_dqueue_empty(&q)) {+            /* this looks up but does NOT consume the queue */+            long int act_node = (long int) igraph_dqueue_back(&q);++            /* get all neighbors of this node */+            tmp = igraph_adjlist_get(&adjlist, act_node);+            if (VECTOR(next_nei)[act_node] == 0) {+                /* this is the first time we've met this vertex,+                     * because next_nei is initialized [0, 0, ...] */+                VECTOR(next_nei)[act_node]++;+                /* back to the queue, same vertex is up again */++            } else if (VECTOR(next_nei)[act_node] <= igraph_vector_int_size(tmp)) {+                /* we've already met this vertex but it has more children */+                long int neighbor = (long int) VECTOR(*tmp)[(long int)+                                    VECTOR(next_nei)[act_node] - 1];+                if (VECTOR(next_nei)[neighbor] == 0) {+                    /* add the root of the other children to the queue */+                    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));+                /* this consumes the queue, since there's nowhere to go */+                igraph_dqueue_pop_back(&q);+                num_seen++;++                if (num_seen % 10000 == 0) {+                    /* time to report progress and allow the user to interrupt */+                    IGRAPH_PROGRESS("Strongly connected components: ",+                                    num_seen * 50.0 / no_of_nodes, NULL);+                    IGRAPH_ALLOW_INTERRUPTION();+                }+            }+        } /* while q */+    }  /* for */++    IGRAPH_PROGRESS("Strongly connected components: ", 50.0, NULL);++    igraph_adjlist_destroy(&adjlist);+    IGRAPH_FINALLY_CLEAN(1);++    IGRAPH_CHECK(igraph_adjlist_init(graph, &adjlist, IGRAPH_IN));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adjlist);++    /* OK, we've the 'out' values for the nodes, let's use them in+     * decreasing order with the help of the next_nei heap */++    igraph_vector_null(&next_nei);             /* mark already added vertices */++    /* number of components built */+    num_seen = 0;+    while (!igraph_vector_empty(&out)) {+        /* consume the vector from the last element */+        long int grandfather = (long int) igraph_vector_pop_back(&out);++        /* been here, done that+         * NOTE: next_nei is initialized as [0, 0, ...] */+        if (VECTOR(next_nei)[grandfather] != 0) {+            continue;+        }++        /* collect all the members of this component */+        igraph_vector_clear(&verts);++        /* this node is gone for any future components */+        VECTOR(next_nei)[grandfather] = 1;+        act_cluster_size = 1;++        /* add to component */+        IGRAPH_CHECK(igraph_vector_push_back(&verts, grandfather));+        IGRAPH_CHECK(igraph_dqueue_push(&q, grandfather));++        num_seen++;+        if (num_seen % 10000 == 0) {+            /* time to report progress and allow the user to interrupt */+            IGRAPH_PROGRESS("Strongly connected components: ",+                            50.0 + num_seen * 50.0 / no_of_nodes, NULL);+            IGRAPH_ALLOW_INTERRUPTION();+        }++        while (!igraph_dqueue_empty(&q)) {+            /* consume the queue from this node */+            long int act_node = (long int) igraph_dqueue_pop_back(&q);+            tmp = igraph_adjlist_get(&adjlist, act_node);+            n = igraph_vector_int_size(tmp);+            for (i = 0; i < n; i++) {+                long int neighbor = (long int) VECTOR(*tmp)[i];+                if (VECTOR(next_nei)[neighbor] != 0) {+                    continue;+                }+                IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));+                VECTOR(next_nei)[neighbor] = 1;+                act_cluster_size++;++                /* add to component */+                IGRAPH_CHECK(igraph_vector_push_back(&verts, neighbor));++                num_seen++;+                if (num_seen % 10000 == 0) {+                    /* time to report progress and allow the user to interrupt */+                    IGRAPH_PROGRESS("Strongly connected components: ",+                                    50.0 + num_seen * 50.0 / no_of_nodes, NULL);+                    IGRAPH_ALLOW_INTERRUPTION();+                }+            }+        }++        /* 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));++        no_of_clusters++;+    }++    IGRAPH_PROGRESS("Strongly connected components: ", 100.0, NULL);++    /* Clean up, return */++    igraph_vector_destroy(&verts);+    igraph_adjlist_destroy(&adjlist);+    igraph_vector_destroy(&out);+    igraph_dqueue_destroy(&q);+    igraph_vector_destroy(&next_nei);+    IGRAPH_FINALLY_CLEAN(6);  /* + 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(), \ref igraph_bridges()+ */++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.+ *+ * </para><para>+ * Somewhat arbitrarily, igraph does not consider comppnents containing+ * a single vertex only as being biconnected. Isolated vertices will+ * not be part of any of the 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_int_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_int_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_int_t *edges = igraph_inclist_get(&inclist,+                                                                 vert);+                                    long int j, nn = igraph_vector_int_size(edges);+                                    for (j = 0; j < nn; j++) {+                                        long int e = (long int) VECTOR(*edges)[j];+                                        long int nei = IGRAPH_OTHER(graph, e, vert);+                                        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;+}+++/* igraph_bridges -- find all bridges in the graph */+/* based on https://www.geeksforgeeks.org/bridge-in-a-graph/ */++static int igraph_i_bridges_rec(const igraph_t *graph, const igraph_inclist_t *il, igraph_integer_t u, igraph_integer_t *time, igraph_vector_t *bridges, igraph_vector_bool_t *visited, igraph_vector_int_t *disc, igraph_vector_int_t *low, igraph_vector_int_t *parent) {+    igraph_vector_int_t *incedges;+    long nc; /* neighbour count */+    long i;++    VECTOR(*visited)[u] = 1;++    *time += 1;++    VECTOR(*disc)[u] = *time;+    VECTOR(*low)[u] = *time;++    incedges = igraph_inclist_get(il, u);+    nc = igraph_vector_int_size(incedges);+    for (i = 0; i < nc; ++i) {+        long edge = (long) VECTOR(*incedges)[i];+        igraph_integer_t v = IGRAPH_TO(graph, edge) == u ? IGRAPH_FROM(graph, edge) : IGRAPH_TO(graph, edge);++        if (! VECTOR(*visited)[v]) {+            VECTOR(*parent)[v] = u;+            IGRAPH_CHECK(igraph_i_bridges_rec(graph, il, v, time, bridges, visited, disc, low, parent));++            VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*low)[v] ? VECTOR(*low)[u] : VECTOR(*low)[v];++            if (VECTOR(*low)[v] > VECTOR(*disc)[u]) {+                IGRAPH_CHECK(igraph_vector_push_back(bridges, edge));+            }+        } else if (v != VECTOR(*parent)[u]) {+            VECTOR(*low)[u] = VECTOR(*low)[u] < VECTOR(*disc)[v] ? VECTOR(*low)[u] : VECTOR(*disc)[v];+        }+    }++    return IGRAPH_SUCCESS;+}++/**+ * \function igraph_bridges+ * Find all bridges in a graph.+ *+ * An edge is a bridge if its removal increases the number of (weakly)+ * connected components in the graph.+ *+ * \param graph The input graph.+ * \param res Pointer to an initialized vector, the+ *    bridges will be stored here as edge indices.+ * \return Error code.+ *+ * Time complexity: O(|V|+|E|), linear in the number of vertices and edges.+ *+ * \sa \ref igraph_articulation_points(), \ref igraph_biconnected_components(), \ref igraph_clusters()+ */++int igraph_bridges(const igraph_t *graph, igraph_vector_t *bridges) {+    igraph_inclist_t il;+    igraph_vector_bool_t visited;+    igraph_vector_int_t disc, low;+    igraph_vector_int_t parent;+    long n;+    long i;+    igraph_integer_t time;++    n = igraph_vcount(graph);++    IGRAPH_CHECK(igraph_inclist_init(graph, &il, IGRAPH_ALL));+    IGRAPH_FINALLY(igraph_inclist_destroy, &il);++    IGRAPH_CHECK(igraph_vector_bool_init(&visited, n));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &visited);++    IGRAPH_CHECK(igraph_vector_int_init(&disc, n));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &disc);++    IGRAPH_CHECK(igraph_vector_int_init(&low, n));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &low);++    IGRAPH_CHECK(igraph_vector_int_init(&parent, n));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &parent);+    for (i = 0; i < n; ++i) {+        VECTOR(parent)[i] = -1;+    }++    igraph_vector_clear(bridges);++    time = 0;+    for (i = 0; i < n; ++i)+        if (! VECTOR(visited)[i]) {+            IGRAPH_CHECK(igraph_i_bridges_rec(graph, &il, i, &time, bridges, &visited, &disc, &low, &parent));+        }++    igraph_vector_int_destroy(&parent);+    igraph_vector_int_destroy(&low);+    igraph_vector_int_destroy(&disc);+    igraph_vector_bool_destroy(&visited);+    igraph_inclist_destroy(&il);+    IGRAPH_FINALLY_CLEAN(5);++    return IGRAPH_SUCCESS;+}
+ igraph/src/conversion.c view
@@ -0,0 +1,953 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_structural.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 direct 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;+}+++/**+ * \ingroup conversion+ * \function igraph_to_prufer+ * \brief Converts a tree to its Pr&uuml;fer sequence+ *+ * A Pr&uuml;fer sequence is a unique sequence of integers associated+ * with a labelled tree. A tree on n >= 2 vertices can be represented by a+ * sequence of n-2 integers, each between 0 and n-1 (inclusive).+ *+ * \param graph Pointer to an initialized graph object which+          must be a tree on n >= 2 vertices.+ * \param prufer A pointer to the integer vector that should hold the Pr&uuml;fer sequence;+                 the vector must be initialized and will be resized to n - 2.+ * \return Error code:+ *          \clist+ *          \cli IGRAPH_ENOMEM+ *             there is not enough memory to perform the operation.+ *          \cli IGRAPH_EINVAL+ *             the graph is not a tree or it is has less than vertices+ *          \endclist+ *+ * \sa \ref igraph_from_prufer()+ *+ */+int igraph_to_prufer(const igraph_t *graph, igraph_vector_int_t* prufer) {+    /* For generating the Prüfer sequence, we enumerate the vertices u of the tree.+       We keep track of the degrees of all vertices, treating vertices+       of degree 0 as removed. We maintain the invariant that all leafs+       that are still contained in the tree are >= u.+       If u is a leaf, we remove it and add its unique neighbor to the prüfer+       sequence. If the removal of u turns the neighbor into a leaf which is < u,+       we repeat the procedure for the new leaf and so on. */+    igraph_integer_t u;+    igraph_vector_t degrees, neighbors;+    igraph_integer_t prufer_index = 0;+    igraph_integer_t n = igraph_vcount(graph);+    igraph_bool_t is_tree = 0;++    IGRAPH_CHECK(igraph_is_tree(graph, &is_tree, NULL, IGRAPH_ALL));++    if (!is_tree) {+        IGRAPH_ERROR("The graph must be a tree", IGRAPH_EINVAL);+    }++    if (n < 2) {+        IGRAPH_ERROR("The tree must have at least 2 vertices", IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_vector_int_resize(prufer, n - 2));+    IGRAPH_VECTOR_INIT_FINALLY(&degrees, n);+    IGRAPH_VECTOR_INIT_FINALLY(&neighbors, 1);++    IGRAPH_CHECK(igraph_degree(graph, &degrees, igraph_vss_all(), IGRAPH_ALL, IGRAPH_NO_LOOPS));++    for (u = 0; u < n; ++u) {+        igraph_integer_t degree = VECTOR(degrees)[u];+        igraph_integer_t leaf = u;++        while (degree == 1 && leaf <= u) {+            igraph_integer_t i;+            igraph_integer_t neighbor = 0;+            igraph_integer_t neighbor_count = 0;++            VECTOR(degrees)[leaf] = 0; /* mark leaf v as deleted */++            IGRAPH_CHECK(igraph_neighbors(graph, &neighbors, leaf, IGRAPH_ALL));++            /* Find the unique remaining neighbor of the leaf */+            neighbor_count = igraph_vector_size(&neighbors);+            for (i = 0; i < neighbor_count; i++) {+                neighbor = VECTOR(neighbors)[i];+                if (VECTOR(degrees)[neighbor] > 0) {+                    break;+                }+            }++            /* remember that we have removed the leaf */+            VECTOR(degrees)[neighbor]--;+            degree = VECTOR(degrees)[neighbor];++            /* Add the neighbor to the prufer sequence unless it is the last vertex+            (i.e. degree == 0) */+            if (degree > 0) {+                VECTOR(*prufer)[prufer_index] = neighbor;+                prufer_index++;+            }+            leaf = neighbor;+        }+    }++    igraph_vector_destroy(&degrees);+    igraph_vector_destroy(&neighbors);+    IGRAPH_FINALLY_CLEAN(2);++    return IGRAPH_SUCCESS;+}
+ igraph/src/cores.c view
@@ -0,0 +1,159 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/cs_add.c view
@@ -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 */+}
+ igraph/src/cs_amd.c view
@@ -0,0 +1,384 @@+/*+ * 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"+/* 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)) ;+}
+ igraph/src/cs_chol.c view
@@ -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 */+}
+ igraph/src/cs_cholsol.c view
@@ -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) ;+}
+ igraph/src/cs_compress.c view
@@ -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 */+}
+ igraph/src/cs_counts.c view
@@ -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 */+} 
+ igraph/src/cs_cumsum.c view
@@ -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]) */+}
+ igraph/src/cs_dfs.c view
@@ -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) ;+}
+ igraph/src/cs_dmperm.c view
@@ -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)) ;+}
+ igraph/src/cs_droptol.c view
@@ -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 */+}
+ igraph/src/cs_dropzeros.c view
@@ -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 */+} 
+ igraph/src/cs_dupl.c view
@@ -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 */+}
+ igraph/src/cs_entry.c view
@@ -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) ;+}
+ igraph/src/cs_ereach.c view
@@ -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,:)*/+}
+ igraph/src/cs_etree.c view
@@ -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)) ;+}
+ igraph/src/cs_fkeep.c view
@@ -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) ;+}
+ igraph/src/cs_gaxpy.c view
@@ -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) ;+}
+ igraph/src/cs_happly.c view
@@ -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) ;+}
+ igraph/src/cs_house.c view
@@ -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) ;+}
+ igraph/src/cs_ipvec.c view
@@ -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) ;+}
+ igraph/src/cs_leaf.c view
@@ -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) */+}
+ igraph/src/cs_load.c view
@@ -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) ;+}
+ igraph/src/cs_lsolve.c view
@@ -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) ;+}
+ igraph/src/cs_ltsolve.c view
@@ -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) ;+}
+ igraph/src/cs_lu.c view
@@ -0,0 +1,107 @@+/*+ * 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,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 */+}
+ igraph/src/cs_lusol.c view
@@ -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) ;+}
+ igraph/src/cs_malloc.c view
@@ -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"+#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 */+}
+ igraph/src/cs_maxtrans.c view
@@ -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)) ;+}
+ igraph/src/cs_multiply.c view
@@ -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 */+}
+ igraph/src/cs_norm.c view
@@ -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) ;+}
+ igraph/src/cs_permute.c view
@@ -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)) ;+}
+ igraph/src/cs_pinv.c view
@@ -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 */+}
+ igraph/src/cs_post.c view
@@ -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 */+}
+ igraph/src/cs_print.c view
@@ -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) ; */+/* } */
+ igraph/src/cs_pvec.c view
@@ -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) ;+}
+ igraph/src/cs_qr.c view
@@ -0,0 +1,94 @@+/*+ * 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 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 */+}
+ igraph/src/cs_qrsol.c view
@@ -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) ;+}
+ igraph/src/cs_randperm.c view
@@ -0,0 +1,47 @@+/*+ * 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 "igraph_random.h"++#include "cs.h"+/* return a random permutation vector, the identity perm, or p = n-1:-1:0.+ * seed = -1 means p = n-1:-1:0.  seed = 0 means p = identity.  otherwise+ * p = random permutation.  */+CS_INT *cs_randperm (CS_INT n, CS_INT seed)+{+    CS_INT *p, k, j, t ;+    if (seed == 0) return (NULL) ;      /* return p = NULL (identity) */+    p = cs_malloc (n, sizeof (CS_INT)) ;   /* allocate result */+    if (!p) return (NULL) ;             /* out of memory */+    for (k = 0 ; k < n ; k++) p [k] = n-k-1 ;+    if (seed == -1) return (p) ;        /* return reverse permutation */+    /* srand (seed) ;                      /\* get new random number seed *\/ */+    RNG_BEGIN();+    for (k = 0 ; k < n ; k++)+    {+        /* j = k + (rand ( ) % (n-k)) ;    /\* j = rand CS_INT in range k to n-1 *\/ */+      j = k + RNG_INTEGER(k, n-1) ;+        t = p [j] ;                     /* swap p[k] and p[j] */+        p [j] = p [k] ;+        p [k] = t ;+    }+    RNG_END();+    return (p) ;+}
+ igraph/src/cs_reach.c view
@@ -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) ;+}
+ igraph/src/cs_scatter.c view
@@ -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) ;+}
+ igraph/src/cs_scc.c view
@@ -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)) ;+}
+ igraph/src/cs_schol.c view
@@ -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)) ;+}
+ igraph/src/cs_spsolve.c view
@@ -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 */+}
+ igraph/src/cs_sqr.c view
@@ -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 */+}
+ igraph/src/cs_symperm.c view
@@ -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 */+}
+ igraph/src/cs_tdfs.c view
@@ -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) ;+}
+ igraph/src/cs_transpose.c view
@@ -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 */+}
+ igraph/src/cs_updown.c view
@@ -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) ;+}
+ igraph/src/cs_usolve.c view
@@ -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) ;+}
+ igraph/src/cs_util.c view
@@ -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 */+}
+ igraph/src/cs_utsolve.c view
@@ -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) ;+}
+ igraph/src/ctype.c view
@@ -0,0 +1,2 @@+#define My_ctype_DEF+#include "ctype.h"
+ igraph/src/d_abs.c view
@@ -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
+ igraph/src/d_acos.c view
@@ -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
+ igraph/src/d_asin.c view
@@ -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
+ igraph/src/d_atan.c view
@@ -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
+ igraph/src/d_atn2.c view
@@ -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
+ igraph/src/d_cnjg.c view
@@ -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
+ igraph/src/d_cos.c view
@@ -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
+ igraph/src/d_cosh.c view
@@ -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
+ igraph/src/d_dim.c view
@@ -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
+ igraph/src/d_exp.c view
@@ -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
+ igraph/src/d_imag.c view
@@ -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
+ igraph/src/d_int.c view
@@ -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
+ igraph/src/d_lg10.c view
@@ -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
+ igraph/src/d_log.c view
@@ -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
+ igraph/src/d_mod.c view
@@ -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
+ igraph/src/d_nint.c view
@@ -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
+ igraph/src/d_prod.c view
@@ -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
+ igraph/src/d_sign.c view
@@ -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
+ igraph/src/d_sin.c view
@@ -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
+ igraph/src/d_sinh.c view
@@ -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
+ igraph/src/d_sqrt.c view
@@ -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
+ igraph/src/d_tan.c view
@@ -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
+ igraph/src/d_tanh.c view
@@ -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
+ igraph/src/dasum.c view
@@ -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_ */+
+ igraph/src/daxpy.c view
@@ -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_ */+
+ igraph/src/dcopy.c view
@@ -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_ */+
+ igraph/src/ddot.c view
@@ -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_ */+
+ igraph/src/decomposition.c view
@@ -0,0 +1,471 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2008-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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, which should be undirected and simple.+ *   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;+    igraph_bool_t simple;++    /***************/+    /* local j, v; */+    /***************/++    long int j, v;++    if (igraph_is_directed(graph)) {+        IGRAPH_ERROR("Maximum cardinality search works on undirected graphs only", IGRAPH_EINVAL);+    }++    igraph_is_simple(graph, &simple);+    if (!simple) {+        IGRAPH_ERROR("Maximum cardinality search works on simple graphs only", IGRAPH_EINVAL);+    }++    if (no_of_nodes == 0) {+        igraph_vector_clear(alpha);+        if (alpham1) {+            igraph_vector_clear(alpham1);+        }+        return IGRAPH_SUCCESS;+    }++    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 */+        /*********************************************/++        if (j < no_of_nodes) {+            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;+}
+ igraph/src/defs.cc view
@@ -0,0 +1,42 @@+#include <cstdlib>+#include <cstdio>+#include "defs.hh"++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++#ifndef USING_R++void+fatal_error(const char* fmt, ...)+{+  va_list ap;+  va_start(ap, fmt);+  fprintf(stderr,"Bliss fatal error: ");+  vfprintf(stderr, fmt, ap);+  fprintf(stderr, "\nAborting!\n");+  va_end(ap);+  exit(1);+}++#endif++}
+ igraph/src/degree_sequence.cpp view
@@ -0,0 +1,490 @@+/*+  Constructing realizations of degree sequences and bi-degree sequences.+  Copyright (C) 2018 Szabolcs Horvat <szhorvat@gmail.com>++  This program is free software; you can redistribute it and/or modify+  it under the terms of the GNU General Public License as published by+  the Free Software Foundation; either version 2 of the License, or+  (at your option) any later version.++  This program is distributed in the hope that it will be useful,+  but WITHOUT ANY WARRANTY; without even the implied warranty of+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+  GNU General Public License for more details.++  You should have received a copy of the GNU General Public License+  along with this program; if not, write to the Free Software+  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+  02110-1301 USA+*/++#include "igraph_constructors.h"+#include "igraph_interface.h"++#include <vector>+#include <list>+#include <algorithm>+#include <utility>+++// (vertex, degree) pair+struct vd_pair {+    long vertex;+    igraph_integer_t degree;++    vd_pair(long vertex, igraph_integer_t degree) : vertex(vertex), degree(degree) {}+};++// (indegree, outdegree)+typedef std::pair<igraph_integer_t, igraph_integer_t> bidegree;++// (vertex, bidegree) pair+struct vbd_pair {+    long vertex;+    bidegree degree;++    vbd_pair(long vertex, bidegree degree) : vertex(vertex), degree(degree) {}+};++// Comparison function for vertex-degree pairs.+// Also used for lexicographic sorting of bi-degrees.+template<typename T> inline bool degree_greater(const T &a, const T &b) {+    return a.degree > b.degree;+}++template<typename T> inline bool degree_less(const T &a, const T &b) {+    return a.degree < b.degree;+}+++// Generate undirected realization as edge-list.+// If largest=true, always choose the vertex with the largest remaining degree to connect up next.+// Otherwise, always choose the one with the smallest remaining degree.+static int igraph_i_havel_hakimi(const igraph_vector_t *deg, igraph_vector_t *edges, bool largest) {+    long n = igraph_vector_size(deg);++    long ec = 0; // number of edges added so far++    std::vector<vd_pair> vertices;+    vertices.reserve(n);+    for (int i = 0; i < n; ++i) {+        vertices.push_back(vd_pair(i, VECTOR(*deg)[i]));+    }++    while (! vertices.empty()) {+        if (largest) {+            std::stable_sort(vertices.begin(), vertices.end(), degree_less<vd_pair>);+        } else {+            std::stable_sort(vertices.begin(), vertices.end(), degree_greater<vd_pair>);+        }++        // take the next vertex to be connected up+        vd_pair vd = vertices.back();+        vertices.pop_back();++        if (vd.degree < 0) {+            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);+        }++        if (vd.degree == 0) {+            continue;+        }++        if (vertices.size() < size_t(vd.degree)) {+            goto fail;+        }++        if (largest) {+            for (int i = 0; i < vd.degree; ++i) {+                if (--(vertices[vertices.size() - 1 - i].degree) < 0) {+                    goto fail;+                }++                VECTOR(*edges)[2 * (ec + i)] = vd.vertex;+                VECTOR(*edges)[2 * (ec + i) + 1] = vertices[vertices.size() - 1 - i].vertex;+            }+        } else {+            // this loop can only be reached if all zero-degree nodes have already been removed+            // therefore decrementing remaining degrees is safe+            for (int i = 0; i < vd.degree; ++i) {+                vertices[i].degree--;++                VECTOR(*edges)[2 * (ec + i)] = vd.vertex;+                VECTOR(*edges)[2 * (ec + i) + 1] = vertices[i].vertex;+            }+        }++        ec += vd.degree;+    }++    return IGRAPH_SUCCESS;++fail:+    IGRAPH_ERROR("The given degree sequence is not realizable", IGRAPH_EINVAL);+}+++// Choose vertices in the order of their IDs.+static int igraph_i_havel_hakimi_index(const igraph_vector_t *deg, igraph_vector_t *edges) {+    long n = igraph_vector_size(deg);++    long ec = 0; // number of edges added so far++    typedef std::list<vd_pair> vlist;+    vlist vertices;+    for (int i = 0; i < n; ++i) {+        vertices.push_back(vd_pair(i, VECTOR(*deg)[i]));+    }++    std::vector<vlist::iterator> pointers;+    pointers.reserve(n);+    for (vlist::iterator it = vertices.begin(); it != vertices.end(); ++it) {+        pointers.push_back(it);+    }++    for (std::vector<vlist::iterator>::iterator pt = pointers.begin(); pt != pointers.end(); ++pt) {+        vertices.sort(degree_greater<vd_pair>);++        vd_pair vd = **pt;+        vertices.erase(*pt);++        if (vd.degree < 0) {+            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);+        }++        if (vd.degree == 0) {+            continue;+        }++        int k;+        vlist::iterator it;+        for (it = vertices.begin(), k = 0;+             k != vd.degree && it != vertices.end();+             ++it, ++k) {+            if (--(it->degree) < 0) {+                goto fail;+            }++            VECTOR(*edges)[2 * (ec + k)] = vd.vertex;+            VECTOR(*edges)[2 * (ec + k) + 1] = it->vertex;+        }+        if (it == vertices.end() && k < vd.degree) {+            goto fail;+        }++        ec += vd.degree;+    }++    return IGRAPH_SUCCESS;++fail:+    IGRAPH_ERROR("The given degree sequence is not realizable", IGRAPH_EINVAL);+}+++inline bool is_nonzero_outdeg(const vbd_pair &vd) {+    return (vd.degree.second != 0);+}+++// The below implementations of the Kleitman-Wang algorithm follow the description in https://arxiv.org/abs/0905.4913++// Realize bi-degree sequence as edge list+// If smallest=true, always choose the vertex with "smallest" bi-degree for connecting up next,+// otherwise choose the "largest" (based on lexicographic bi-degree ordering).+static int igraph_i_kleitman_wang(const igraph_vector_t *outdeg, const igraph_vector_t *indeg, igraph_vector_t *edges, bool smallest) {+    long n = igraph_vector_size(indeg); // number of vertices++    long ec = 0; // number of edges added so far++    std::vector<vbd_pair> vertices;+    vertices.reserve(n);+    for (int i = 0; i < n; ++i) {+        vertices.push_back(vbd_pair(i, bidegree(VECTOR(*indeg)[i], VECTOR(*outdeg)[i])));+    }++    while (true) {+        // sort vertices by (in, out) degree pairs in decreasing order+        std::stable_sort(vertices.begin(), vertices.end(), degree_greater<vbd_pair>);++        // remove (0,0)-degree vertices+        while (!vertices.empty() && vertices.back().degree == bidegree(0, 0)) {+            vertices.pop_back();+        }++        // if no vertices remain, stop+        if (vertices.empty()) {+            break;+        }++        // choose a vertex the out-stubs of which will be connected+        vbd_pair *vdp;+        if (smallest) {+            vdp = &*std::find_if(vertices.rbegin(), vertices.rend(), is_nonzero_outdeg);+        } else {+            vdp = &*std::find_if(vertices.begin(), vertices.end(), is_nonzero_outdeg);+        }+++        if (vdp->degree.first < 0 || vdp->degree.second < 0) {+            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);+        }++        // are there a sufficient number of other vertices to connect to?+        if (vertices.size() < vdp->degree.second - 1) {+            goto fail;+        }++        // create the connections+        int k = 0;+        for (std::vector<vbd_pair>::iterator it = vertices.begin();+             k < vdp->degree.second;+             ++it) {+            if (it->vertex == vdp->vertex) {+                continue;    // do not create a self-loop+            }+            if (--(it->degree.first) < 0) {+                goto fail;+            }++            VECTOR(*edges)[2 * (ec + k)] = vdp->vertex;+            VECTOR(*edges)[2 * (ec + k) + 1] = it->vertex;++            k++;+        }++        ec += vdp->degree.second;+        vdp->degree.second = 0;+    }++    return IGRAPH_SUCCESS;++fail:+    IGRAPH_ERROR("The given directed degree sequence is not realizable", IGRAPH_EINVAL);+}+++// Choose vertices in the order of their IDs.+static int igraph_i_kleitman_wang_index(const igraph_vector_t *outdeg, const igraph_vector_t *indeg, igraph_vector_t *edges) {+    long n = igraph_vector_size(indeg); // number of vertices++    long ec = 0; // number of edges added so far++    typedef std::list<vbd_pair> vlist;+    vlist vertices;+    for (int i = 0; i < n; ++i) {+        vertices.push_back(vbd_pair(i, bidegree(VECTOR(*indeg)[i], VECTOR(*outdeg)[i])));+    }++    std::vector<vlist::iterator> pointers;+    pointers.reserve(n);+    for (vlist::iterator it = vertices.begin(); it != vertices.end(); ++it) {+        pointers.push_back(it);+    }++    for (std::vector<vlist::iterator>::iterator pt = pointers.begin(); pt != pointers.end(); ++pt) {+        // sort vertices by (in, out) degree pairs in decreasing order+        // note: std::list::sort does a stable sort+        vertices.sort(degree_greater<vbd_pair>);++        // choose a vertex the out-stubs of which will be connected+        vbd_pair &vd = **pt;++        if (vd.degree.second == 0) {+            continue;+        }++        if (vd.degree.first < 0 || vd.degree.second < 0) {+            IGRAPH_ERROR("Vertex degrees must be positive", IGRAPH_EINVAL);+        }++        int k = 0;+        vlist::iterator it;+        for (it = vertices.begin();+             k != vd.degree.second && it != vertices.end();+             ++it) {+            if (it->vertex == vd.vertex) {+                continue;+            }++            if (--(it->degree.first) < 0) {+                goto fail;+            }++            VECTOR(*edges)[2 * (ec + k)] = vd.vertex;+            VECTOR(*edges)[2 * (ec + k) + 1] = it->vertex;++            ++k;+        }+        if (it == vertices.end() && k < vd.degree.second) {+            goto fail;+        }++        ec += vd.degree.second;+        vd.degree.second = 0;+    }++    return IGRAPH_SUCCESS;++fail:+    IGRAPH_ERROR("The given directed degree sequence is not realizable", IGRAPH_EINVAL);+}+++static int igraph_i_realize_undirected_degree_sequence(+    igraph_t *graph,+    const igraph_vector_t *deg,+    igraph_realize_degseq_t method) {+    long node_count = igraph_vector_size(deg);+    long deg_sum = long(igraph_vector_sum(deg));++    if (deg_sum % 2 != 0) {+        IGRAPH_ERROR("The sum of degrees must be even for an undirected graph", IGRAPH_EINVAL);+    }++    igraph_vector_t edges;+    IGRAPH_CHECK(igraph_vector_init(&edges, deg_sum));+    IGRAPH_FINALLY(igraph_vector_destroy, &edges);++    switch (method) {+    case IGRAPH_REALIZE_DEGSEQ_SMALLEST:+        IGRAPH_CHECK(igraph_i_havel_hakimi(deg, &edges, false));+        break;+    case IGRAPH_REALIZE_DEGSEQ_LARGEST:+        IGRAPH_CHECK(igraph_i_havel_hakimi(deg, &edges, true));+        break;+    case IGRAPH_REALIZE_DEGSEQ_INDEX:+        IGRAPH_CHECK(igraph_i_havel_hakimi_index(deg, &edges));+        break;+    default:+        IGRAPH_ERROR("Invalid degree sequence realization method", IGRAPH_EINVAL);+    }++    igraph_create(graph, &edges, igraph_integer_t(node_count), false);++    igraph_vector_destroy(&edges);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}+++static int igraph_i_realize_directed_degree_sequence(+    igraph_t *graph,+    const igraph_vector_t *outdeg,+    const igraph_vector_t *indeg,+    igraph_realize_degseq_t method) {+    long node_count = igraph_vector_size(outdeg);+    long edge_count = long(igraph_vector_sum(outdeg));++    if (igraph_vector_size(indeg) != node_count) {+        IGRAPH_ERROR("In- and out-degree sequences must have the same length", IGRAPH_EINVAL);+    }+    if (igraph_vector_sum(indeg) != edge_count) {+        IGRAPH_ERROR("In- and out-degree sequences do not sum to the same value", IGRAPH_EINVAL);+    }++    igraph_vector_t edges;+    IGRAPH_CHECK(igraph_vector_init(&edges, 2 * edge_count));+    IGRAPH_FINALLY(igraph_vector_destroy, &edges);++    switch (method) {+    case IGRAPH_REALIZE_DEGSEQ_SMALLEST:+        IGRAPH_CHECK(igraph_i_kleitman_wang(outdeg, indeg, &edges, true));+        break;+    case IGRAPH_REALIZE_DEGSEQ_LARGEST:+        IGRAPH_CHECK(igraph_i_kleitman_wang(outdeg, indeg, &edges, false));+        break;+    case IGRAPH_REALIZE_DEGSEQ_INDEX:+        IGRAPH_CHECK(igraph_i_kleitman_wang_index(outdeg, indeg, &edges));+        break;+    default:+        IGRAPH_ERROR("Invalid bi-degree sequence realization method", IGRAPH_EINVAL);+    }++    igraph_create(graph, &edges, igraph_integer_t(node_count), true);++    igraph_vector_destroy(&edges);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}+++/**+ * \ingroup generators+ * \function igraph_realize_degree_sequence+ * \brief Generates a graph with the given degree sequence+ *+ * This function constructs a simple graph that realizes the given degree sequence+ * using the Havel-Hakimi algorithm, or the given (directed) out- and in-degree+ * sequences using the related Kleitman-Wang algorithm.+ *+ * The algorithms work by choosing an arbitrary vertex and connecting all its stubs+ * to other vertices of highest degree.  In the directed case, the "highest" (in, out) degree+ * pairs are determined based on lexicographic ordering.+ *+ * The \c method parameter controls the order in which the vertices to be connected are chosen.+ *+ * \param graph Pointer to an uninitialized graph object.+ * \param outdeg The degree sequence for a simple undirected graph+ *        (if \p indeg is NULL or of length zero), or the out-degree sequence of+ *        a directed graph (if \p indeg is of nonzero size).+ * \param indeg 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_REALIZE_DEGSEQ_SMALLEST+ *          The vertex with smallest remaining degree is selected first. The result is usually+ *          a graph with high negative degree assortativity. In the undirected case, this method+ *          is guaranteed to generate a connected graph, provided that a connected realization exists.+ *          See http://szhorvat.net/pelican/hh-connected-graphs.html for a proof.+ *          In the directed case it tends to generate weakly connected graphs, but this is not+ *          guaranteed.+ *          \cli IGRAPH_REALIZE_DEGSEQ_LARGEST+ *          The vertex with the largest remaining degree is selected first. The result+ *          is usually a graph with high positive degree assortativity, and is often disconnected.+ *          \cli IGRAPH_REALIZE_DEGSEQ_INDEX+ *          The vertices are selected in order of their index (i.e. their position in the degree vector).+ *          Note that sorting the degree vector and using the \c INDEX method is not equivalent+ *          to the \c SMALLEST method above, as \c SMALLEST uses the smallest \em remaining+ *          degree for selecting vertices, not the smallest \em initial degree.+ *         \endclist+ * \return Error code:+ *          \clist+ *          \cli IGRAPH_ENOMEM+ *           There is not enough memory to perform the operation.+ *          \cli IGRAPH_EINVAL+ *           Invalid method parameter, or invalid in- and/or out-degree vectors.+ *           The degree vectors should be non-negative, the length+ *           and sum of \p outdeg and \p indeg should match for directed graphs.+ *          \endclist+ *+ * \sa  \ref igraph_is_graphical_degree_sequence()+ *      \ref igraph_degree_sequence_game()+ *      \ref igraph_k_regular_game()+ *      \ref igraph_rewire()+ *+ */++int igraph_realize_degree_sequence(+    igraph_t *graph,+    const igraph_vector_t *outdeg, const igraph_vector_t *indeg,+    igraph_realize_degseq_t method) {+    long n = igraph_vector_size(outdeg);+    if (n != igraph_integer_t(n)) { // does the vector size fit into an igraph_integer_t ?+        IGRAPH_ERROR("Degree sequence vector too long", IGRAPH_EINVAL);+    }++    bool directed = bool(indeg) && igraph_vector_size(indeg) != 0;++    try {+        if (directed) {+            return igraph_i_realize_directed_degree_sequence(graph, outdeg, indeg, method);+        } else {+            return igraph_i_realize_undirected_degree_sequence(graph, outdeg, method);+        }+    } catch (const std::bad_alloc &) {+        IGRAPH_ERROR("Cannot realize degree sequence due to insufficient memory", IGRAPH_ENOMEM);+    }+}
+ igraph/src/derf_.c view
@@ -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
+ igraph/src/derfc_.c view
@@ -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
+ igraph/src/dfe.c view
@@ -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
+ igraph/src/dgebak.c view
@@ -0,0 +1,301 @@+/*  -- 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"++/* > \brief \b DGEBAK   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGEBAK + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgebak.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgebak.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgebak.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGEBAK( JOB, SIDE, N, ILO, IHI, SCALE, M, V, LDV,   +                            INFO )   ++         CHARACTER          JOB, SIDE   +         INTEGER            IHI, ILO, INFO, LDV, M, N   +         DOUBLE PRECISION   SCALE( * ), V( LDV, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOB   +   > \verbatim   +   >          JOB is 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.   +   > \endverbatim   +   >   +   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'R':  V contains right eigenvectors;   +   >          = 'L':  V contains left eigenvectors.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of rows of the matrix V.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is INTEGER   +   >          The integers ILO and IHI determined by DGEBAL.   +   >          1 <= ILO <= IHI <= N, if N > 0; ILO=1 and IHI=0, if N=0.   +   > \endverbatim   +   >   +   > \param[in] SCALE   +   > \verbatim   +   >          SCALE is DOUBLE PRECISION array, dimension (N)   +   >          Details of the permutation and scaling factors, as returned   +   >          by DGEBAL.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of columns of the matrix V.  M >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] V   +   > \verbatim   +   >          V is 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.   +   > \endverbatim   +   >   +   > \param[in] LDV   +   > \verbatim   +   >          LDV is INTEGER   +   >          The leading dimension of the array V. LDV >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleGEcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgebal.c view
@@ -0,0 +1,466 @@+/*  -- 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;++/* > \brief \b DGEBAL   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGEBAL + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgebal.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgebal.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgebal.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGEBAL( JOB, N, A, LDA, ILO, IHI, SCALE, INFO )   ++         CHARACTER          JOB   +         INTEGER            IHI, ILO, INFO, LDA, N   +         DOUBLE PRECISION   A( LDA, * ), SCALE( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOB   +   > \verbatim   +   >          JOB is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is DOUBLE 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   > \param[out] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[out] SCALE   +   > \verbatim   +   >          SCALE is DOUBLE 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit.   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2013   ++   > \ingroup doubleGEcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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   +   > \endverbatim   +   >   +    =====================================================================   +   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 doublereal igraphdnrm2_(integer *, doublereal *, integer *);+    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 computational routine (version 3.5.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2013   +++    =====================================================================   +++       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__) {++	i__2 = l - k + 1;+	c__ = igraphdnrm2_(&i__2, &a[k + i__ * a_dim1], &c__1);+	i__2 = l - k + 1;+	r__ = igraphdnrm2_(&i__2, &a[i__ + k * a_dim1], lda);+	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_ */+
+ igraph/src/dgeev.c view
@@ -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 integer c__0 = 0;+static integer c_n1 = -1;++/* > \brief <b> DGEEV computes the eigenvalues and, optionally, the left and/or right eigenvectors for GE matr+ices</b>   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGEEV + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgeev.f+">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgeev.f+">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgeev.f+">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGEEV( JOBVL, JOBVR, N, A, LDA, WR, WI, VL, LDVL, VR,   +                           LDVR, WORK, LWORK, INFO )   ++         CHARACTER          JOBVL, JOBVR   +         INTEGER            INFO, LDA, LDVL, LDVR, LWORK, N   +         DOUBLE PRECISION   A( LDA, * ), VL( LDVL, * ), VR( LDVR, * ),   +        $                   WI( * ), WORK( * ), WR( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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)**H * A = lambda(j) * u(j)**H   +   > where u(j)**H denotes the conjugate-transpose of u(j).   +   >   +   > The computed eigenvectors are normalized to have Euclidean norm   +   > equal to 1 and largest component real.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOBVL   +   > \verbatim   +   >          JOBVL is CHARACTER*1   +   >          = 'N': left eigenvectors of A are not computed;   +   >          = 'V': left eigenvectors of A are computed.   +   > \endverbatim   +   >   +   > \param[in] JOBVR   +   > \verbatim   +   >          JOBVR is CHARACTER*1   +   >          = 'N': right eigenvectors of A are not computed;   +   >          = 'V': right eigenvectors of A are computed.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A. N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,N)   +   >          On entry, the N-by-N matrix A.   +   >          On exit, A has been overwritten.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] WI   +   > \verbatim   +   >          WI is 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.   +   > \endverbatim   +   >   +   > \param[out] VL   +   > \verbatim   +   >          VL is 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).   +   > \endverbatim   +   >   +   > \param[in] LDVL   +   > \verbatim   +   >          LDVL is INTEGER   +   >          The leading dimension of the array VL.  LDVL >= 1; if   +   >          JOBVL = 'V', LDVL >= N.   +   > \endverbatim   +   >   +   > \param[out] VR   +   > \verbatim   +   >          VR is 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).   +   > \endverbatim   +   >   +   > \param[in] LDVR   +   > \verbatim   +   >          LDVR is INTEGER   +   >          The leading dimension of the array VR.  LDVR >= 1; if   +   >          JOBVR = 'V', LDVR >= N.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleGEeigen   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgeevx.c view
@@ -0,0 +1,811 @@+/*  -- 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;++/* > \brief <b> DGEEVX computes the eigenvalues and, optionally, the left and/or right eigenvectors for GE mat+rices</b>   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGEEVX + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgeevx.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgeevx.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgeevx.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGEEVX( BALANC, JOBVL, JOBVR, SENSE, N, A, LDA, WR, WI,   +                            VL, LDVL, VR, LDVR, ILO, IHI, SCALE, ABNRM,   +                            RCONDE, RCONDV, WORK, LWORK, IWORK, INFO )   ++         CHARACTER          BALANC, JOBVL, JOBVR, SENSE   +         INTEGER            IHI, ILO, INFO, LDA, LDVL, LDVR, LWORK, N   +         DOUBLE PRECISION   ABNRM   +         INTEGER            IWORK( * )   +         DOUBLE PRECISION   A( LDA, * ), RCONDE( * ), RCONDV( * ),   +        $                   SCALE( * ), VL( LDVL, * ), VR( LDVR, * ),   +        $                   WI( * ), WORK( * ), WR( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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)**H * A = lambda(j) * u(j)**H   +   > where u(j)**H denotes the conjugate-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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] BALANC   +   > \verbatim   +   >          BALANC is 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.   +   > \endverbatim   +   >   +   > \param[in] JOBVL   +   > \verbatim   +   >          JOBVL is 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'.   +   > \endverbatim   +   >   +   > \param[in] JOBVR   +   > \verbatim   +   >          JOBVR is 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'.   +   > \endverbatim   +   >   +   > \param[in] SENSE   +   > \verbatim   +   >          SENSE is 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').   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A. N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] WI   +   > \verbatim   +   >          WI is 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.   +   > \endverbatim   +   >   +   > \param[out] VL   +   > \verbatim   +   >          VL is 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).   +   > \endverbatim   +   >   +   > \param[in] LDVL   +   > \verbatim   +   >          LDVL is INTEGER   +   >          The leading dimension of the array VL.  LDVL >= 1; if   +   >          JOBVL = 'V', LDVL >= N.   +   > \endverbatim   +   >   +   > \param[out] VR   +   > \verbatim   +   >          VR is 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).   +   > \endverbatim   +   >   +   > \param[in] LDVR   +   > \verbatim   +   >          LDVR is INTEGER   +   >          The leading dimension of the array VR.  LDVR >= 1, and if   +   >          JOBVR = 'V', LDVR >= N.   +   > \endverbatim   +   >   +   > \param[out] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[out] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[out] SCALE   +   > \verbatim   +   >          SCALE is 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.   +   > \endverbatim   +   >   +   > \param[out] ABNRM   +   > \verbatim   +   >          ABNRM is DOUBLE PRECISION   +   >          The one-norm of the balanced matrix (the maximum   +   >          of the sum of absolute values of elements of any column).   +   > \endverbatim   +   >   +   > \param[out] RCONDE   +   > \verbatim   +   >          RCONDE is DOUBLE PRECISION array, dimension (N)   +   >          RCONDE(j) is the reciprocal condition number of the j-th   +   >          eigenvalue.   +   > \endverbatim   +   >   +   > \param[out] RCONDV   +   > \verbatim   +   >          RCONDV is DOUBLE PRECISION array, dimension (N)   +   >          RCONDV(j) is the reciprocal condition number of the j-th   +   >          right eigenvector.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (2*N-2)   +   >          If SENSE = 'N' or 'E', not referenced.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleGEeigen   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgehd2.c view
@@ -0,0 +1,255 @@+/*  -- 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;++/* > \brief \b DGEHD2 reduces a general square matrix to upper Hessenberg form using an unblocked algorithm. +  ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGEHD2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgehd2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgehd2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgehd2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGEHD2( N, ILO, IHI, A, LDA, TAU, WORK, INFO )   ++         INTEGER            IHI, ILO, INFO, LDA, N   +         DOUBLE PRECISION   A( LDA, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DGEHD2 reduces a real general matrix A to upper Hessenberg form H by   +   > an orthogonal similarity transformation:  Q**T * A * Q = H .   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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).   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (N-1)   +   >          The scalar factors of the elementary reflectors (see Further   +   >          Details).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit.   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleGEcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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).   +   > \endverbatim   +   >   +    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgehrd.c view
@@ -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"++/* 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.;++/* > \brief \b DGEHRD   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGEHRD + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgehrd.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgehrd.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgehrd.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGEHRD( N, ILO, IHI, A, LDA, TAU, WORK, LWORK, INFO )   ++         INTEGER            IHI, ILO, INFO, LDA, LWORK, N   +         DOUBLE PRECISION  A( LDA, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DGEHRD reduces a real general matrix A to upper Hessenberg form H by   +   > an orthogonal similarity transformation:  Q**T * A * Q = H .   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (LWORK)   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleGEcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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.)   +   > \endverbatim   +   >   +    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgemm.c view
@@ -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_ */+
+ igraph/src/dgemv.c view
@@ -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_ */+
+ igraph/src/dgeqr2.c view
@@ -0,0 +1,220 @@+/*  -- 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;++/* > \brief \b DGEQR2 computes the QR factorization of a general rectangular matrix using an unblocked algorit+hm.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGEQR2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgeqr2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgeqr2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgeqr2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGEQR2( M, N, A, LDA, TAU, WORK, INFO )   ++         INTEGER            INFO, LDA, M, N   +         DOUBLE PRECISION   A( LDA, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DGEQR2 computes a QR factorization of a real m by n matrix A:   +   > A = Q * R.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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).   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (min(M,N))   +   >          The scalar factors of the elementary reflectors (see Further   +   >          Details).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0: successful exit   +   >          < 0: if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleGEcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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).   +   > \endverbatim   +   >   +    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dger.c view
@@ -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_ */+
+ igraph/src/dgesv.c view
@@ -0,0 +1,201 @@+/*  -- 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"++/* > \brief <b> DGESV computes the solution to system of linear equations A * X = B for GE matrices</b>   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGESV + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgesv.f+">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgesv.f+">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgesv.f+">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGESV( N, NRHS, A, LDA, IPIV, B, LDB, INFO )   ++         INTEGER            INFO, LDA, LDB, N, NRHS   +         INTEGER            IPIV( * )   +         DOUBLE PRECISION   A( LDA, * ), B( LDB, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of linear equations, i.e., the order of the   +   >          matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] NRHS   +   > \verbatim   +   >          NRHS is INTEGER   +   >          The number of right hand sides, i.e., the number of columns   +   >          of the matrix B.  NRHS >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] IPIV   +   > \verbatim   +   >          IPIV is INTEGER array, dimension (N)   +   >          The pivot indices that define the permutation matrix P;   +   >          row i of the matrix was interchanged with row IPIV(i).   +   > \endverbatim   +   >   +   > \param[in,out] B   +   > \verbatim   +   >          B is 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.   +   > \endverbatim   +   >   +   > \param[in] LDB   +   > \verbatim   +   >          LDB is INTEGER   +   >          The leading dimension of the array B.  LDB >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleGEsolve   ++    =====================================================================   +   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.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgetf2.c view
@@ -0,0 +1,244 @@+/*  -- 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.;++/* > \brief \b DGETF2 computes the LU factorization of a general m-by-n matrix using partial pivoting with row+ interchanges (unblocked algorithm).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGETF2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgetf2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgetf2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgetf2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGETF2( M, N, A, LDA, IPIV, INFO )   ++         INTEGER            INFO, LDA, M, N   +         INTEGER            IPIV( * )   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] IPIV   +   > \verbatim   +   >          IPIV is 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).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleGEcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgetrf.c view
@@ -0,0 +1,270 @@+/*  -- 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.;++/* > \brief \b DGETRF   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGETRF + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgetrf.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgetrf.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgetrf.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGETRF( M, N, A, LDA, IPIV, INFO )   ++         INTEGER            INFO, LDA, M, N   +         INTEGER            IPIV( * )   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] IPIV   +   > \verbatim   +   >          IPIV is 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).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleGEcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgetrs.c view
@@ -0,0 +1,246 @@+/*  -- 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;++/* > \brief \b DGETRS   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DGETRS + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dgetrs.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dgetrs.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dgetrs.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DGETRS( TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO )   ++         CHARACTER          TRANS   +         INTEGER            INFO, LDA, LDB, N, NRHS   +         INTEGER            IPIV( * )   +         DOUBLE PRECISION   A( LDA, * ), B( LDB, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is 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)   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] NRHS   +   > \verbatim   +   >          NRHS is INTEGER   +   >          The number of right hand sides, i.e., the number of columns   +   >          of the matrix B.  NRHS >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,N)   +   >          The factors L and U from the factorization A = P*L*U   +   >          as computed by DGETRF.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] IPIV   +   > \verbatim   +   >          IPIV is INTEGER array, dimension (N)   +   >          The pivot indices from DGETRF; for 1<=i<=N, row i of the   +   >          matrix was interchanged with row IPIV(i).   +   > \endverbatim   +   >   +   > \param[in,out] B   +   > \verbatim   +   >          B is DOUBLE PRECISION array, dimension (LDB,NRHS)   +   >          On entry, the right hand side matrix B.   +   >          On exit, the solution matrix X.   +   > \endverbatim   +   >   +   > \param[in] LDB   +   > \verbatim   +   >          LDB is INTEGER   +   >          The leading dimension of the array B.  LDB >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleGEcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dgetv0.c view
@@ -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 = 0;+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, +	    integer *);+    IGRAPH_F77_SAVE integer iter;+    IGRAPH_F77_SAVE logical orth;+    integer nopx = 0;+    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 = 0;+    extern /* Subroutine */ int igraphdvout_(integer *, integer *, doublereal *, +	    integer *, char *, ftnlen);+    integer mgetv0 = 0;+    real tgetv0 = 0;+    IGRAPH_F77_SAVE doublereal rnorm0;+    extern /* Subroutine */ int igraphsecond_(real *);+    integer logfil, ndigit;+    extern /* Subroutine */ int igraphdlarnv_(integer *, integer *, integer *, +	    doublereal *);+    IGRAPH_F77_SAVE integer msglvl;+    real tmvopx = 0;+++/*     %----------------------------------------------------%   +       | 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_ */+
+ igraph/src/dhseqr.c view
@@ -0,0 +1,574 @@+/*  -- 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;++/* > \brief \b DHSEQR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DHSEQR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dhseqr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dhseqr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dhseqr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DHSEQR( JOB, COMPZ, N, ILO, IHI, H, LDH, WR, WI, Z,   +                            LDZ, WORK, LWORK, INFO )   ++         INTEGER            IHI, ILO, INFO, LDH, LDZ, LWORK, N   +         CHARACTER          COMPZ, JOB   +         DOUBLE PRECISION   H( LDH, * ), WI( * ), WORK( * ), WR( * ),   +        $                   Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOB   +   > \verbatim   +   >          JOB is CHARACTER*1   +   >           = 'E':  compute eigenvalues only;   +   >           = 'S':  compute eigenvalues and the Schur form T.   +   > \endverbatim   +   >   +   > \param[in] COMPZ   +   > \verbatim   +   >          COMPZ is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >           The order of the matrix H.  N .GE. 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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 ZGEHRD   +   >           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.   +   > \endverbatim   +   >   +   > \param[in,out] H   +   > \verbatim   +   >          H is 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.   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is INTEGER   +   >           The leading dimension of the array H. LDH .GE. max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] WI   +   > \verbatim   +   >          WI is 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).   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.)   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >           The leading dimension of the array Z.  if COMPZ = 'I' or   +   >           COMPZ = 'V', then LDZ.GE.MAX(1,N).  Otherwize, LDZ.GE.1.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (LWORK)   +   >           On exit, if INFO = 0, WORK(1) returns an estimate of   +   >           the optimal value for LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++   > \par Contributors:   +    ==================   +   >   +   >       Karen Braman and Ralph Byers, Department of Mathematics,   +   >       University of Kansas, USA   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >             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.   +   > \endverbatim   ++   > \par 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.   +   > \n   +   >       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.   ++    =====================================================================   +   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.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       ==== 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_ */+
+ igraph/src/disnan.c view
@@ -0,0 +1,95 @@+/*  -- 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"++/* > \brief \b DISNAN tests input for NaN.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DISNAN + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/disnan.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/disnan.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/disnan.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         LOGICAL FUNCTION DISNAN( DIN )   ++         DOUBLE PRECISION   DIN   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DISNAN returns .TRUE. if its argument is NaN, and .FALSE.   +   > otherwise.  To be replaced by the Fortran 2003 intrinsic in the   +   > future.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] DIN   +   > \verbatim   +   >          DIN is DOUBLE PRECISION   +   >          Input to test for NaN.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+logical igraphdisnan_(doublereal *din)+{+    /* System generated locals */+    logical ret_val;++    /* Local variables */+    extern logical igraphdlaisnan_(doublereal *, doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ===================================================================== */++    ret_val = igraphdlaisnan_(din, din);+    return ret_val;+} /* igraphdisnan_ */+
+ igraph/src/distances.c view
@@ -0,0 +1,211 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/dlabad.c view
@@ -0,0 +1,118 @@+/*  -- 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"++/* > \brief \b DLABAD   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLABAD + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlabad.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlabad.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlabad.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLABAD( SMALL, LARGE )   ++         DOUBLE PRECISION   LARGE, SMALL   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in,out] SMALL   +   > \verbatim   +   >          SMALL is 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.   +   > \endverbatim   +   >   +   > \param[in,out] LARGE   +   > \verbatim   +   >          LARGE is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   Subroutine */ int igraphdlabad_(doublereal *small, doublereal *large)+{+    /* Builtin functions */+    double d_lg10(doublereal *), sqrt(doublereal);+++/*  -- LAPACK auxiliary routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlacn2.c view
@@ -0,0 +1,332 @@+/*  -- 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.;++/* > \brief \b DLACN2 estimates the 1-norm of a square matrix, using reverse communication for evaluating matr+ix-vector products.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLACN2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlacn2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlacn2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlacn2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLACN2( N, V, X, ISGN, EST, KASE, ISAVE )   ++         INTEGER            KASE, N   +         DOUBLE PRECISION   EST   +         INTEGER            ISGN( * ), ISAVE( 3 )   +         DOUBLE PRECISION   V( * ), X( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLACN2 estimates the 1-norm of a square, real matrix A.   +   > Reverse communication is used for evaluating matrix-vector products.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >         The order of the matrix.  N >= 1.   +   > \endverbatim   +   >   +   > \param[out] V   +   > \verbatim   +   >          V is DOUBLE PRECISION array, dimension (N)   +   >         On the final return, V = A*W,  where  EST = norm(V)/norm(W)   +   >         (W is not returned).   +   > \endverbatim   +   >   +   > \param[in,out] X   +   > \verbatim   +   >          X is 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.   +   > \endverbatim   +   >   +   > \param[out] ISGN   +   > \verbatim   +   >          ISGN is INTEGER array, dimension (N)   +   > \endverbatim   +   >   +   > \param[in,out] EST   +   > \verbatim   +   >          EST is 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).   +   > \endverbatim   +   >   +   > \param[in,out] KASE   +   > \verbatim   +   >          KASE is 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.   +   > \endverbatim   +   >   +   > \param[in,out] ISAVE   +   > \verbatim   +   >          ISAVE is INTEGER array, dimension (3)   +   >         ISAVE is used to save variables between calls to DLACN2   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  Originally named SONEST, dated March 16, 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)   +   > \endverbatim   ++   > \par Contributors:   +    ==================   +   >   +   >     Nick Higham, University of Manchester   ++   > \par References:   +    ================   +   >   +   >  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.   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlacpy.c view
@@ -0,0 +1,182 @@+/*  -- 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"++/* > \brief \b DLACPY copies all or part of one two-dimensional array to another.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLACPY + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlacpy.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlacpy.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlacpy.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLACPY( UPLO, M, N, A, LDA, B, LDB )   ++         CHARACTER          UPLO   +         INTEGER            LDA, LDB, M, N   +         DOUBLE PRECISION   A( LDA, * ), B( LDB, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLACPY copies all or part of a two-dimensional matrix A to another   +   > matrix B.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is 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   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] B   +   > \verbatim   +   >          B is DOUBLE PRECISION array, dimension (LDB,N)   +   >          On exit, B = A in the locations specified by UPLO.   +   > \endverbatim   +   >   +   > \param[in] LDB   +   > \verbatim   +   >          LDB is INTEGER   +   >          The leading dimension of the array B.  LDB >= max(1,M).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dladiv.c view
@@ -0,0 +1,246 @@+/*  -- 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"++/* > \brief \b DLADIV performs complex division in real arithmetic, avoiding unnecessary overflow.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLADIV + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dladiv.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dladiv.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dladiv.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLADIV( A, B, C, D, P, Q )   ++         DOUBLE PRECISION   A, B, C, D, P, Q   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLADIV performs complex division in  real arithmetic   +   >   +   >                       a + i*b   +   >            p + i*q = ---------   +   >                       c + i*d   +   >   +   > The algorithm is due to Michael Baudin and Robert L. Smith   +   > and can be found in the paper   +   > "A Robust Complex Division in Scilab"   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] C   +   > \verbatim   +   >          C is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION   +   >          The scalars a, b, c, and d in the above expression.   +   > \endverbatim   +   >   +   > \param[out] P   +   > \verbatim   +   >          P is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] Q   +   > \verbatim   +   >          Q is DOUBLE PRECISION   +   >          The scalars p and q in the above expression.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date January 2013   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   Subroutine */ int igraphdladiv_(doublereal *a, doublereal *b, doublereal *c__, +	doublereal *d__, doublereal *p, doublereal *q)+{+    /* System generated locals */+    doublereal d__1, d__2;++    /* Local variables */+    doublereal s, aa, ab, bb, cc, cd, dd, be, un, ov, eps;+    extern doublereal igraphdlamch_(char *);+    extern /* Subroutine */ int dladiv1_(doublereal *, doublereal *, +	    doublereal *, doublereal *, doublereal *, doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.5.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       January 2013   +++    ===================================================================== */++++    aa = *a;+    bb = *b;+    cc = *c__;+    dd = *d__;+/* Computing MAX */+    d__1 = abs(*a), d__2 = abs(*b);+    ab = max(d__1,d__2);+/* Computing MAX */+    d__1 = abs(*c__), d__2 = abs(*d__);+    cd = max(d__1,d__2);+    s = 1.;+    ov = igraphdlamch_("Overflow threshold");+    un = igraphdlamch_("Safe minimum");+    eps = igraphdlamch_("Epsilon");+    be = 2. / (eps * eps);+    if (ab >= ov * .5) {+	aa *= .5;+	bb *= .5;+	s *= 2.;+    }+    if (cd >= ov * .5) {+	cc *= .5;+	dd *= .5;+	s *= .5;+    }+    if (ab <= un * 2. / eps) {+	aa *= be;+	bb *= be;+	s /= be;+    }+    if (cd <= un * 2. / eps) {+	cc *= be;+	dd *= be;+	s *= be;+    }+    if (abs(*d__) <= abs(*c__)) {+	dladiv1_(&aa, &bb, &cc, &dd, p, q);+    } else {+	dladiv1_(&bb, &aa, &dd, &cc, p, q);+	*q = -(*q);+    }+    *p *= s;+    *q *= s;++    return 0;++/*     End of DLADIV */++} /* igraphdladiv_   ++   Subroutine */ int dladiv1_(doublereal *a, doublereal *b, doublereal *c__, +	doublereal *d__, doublereal *p, doublereal *q)+{+    doublereal r__, t;+    extern doublereal dladiv2_(doublereal *, doublereal *, doublereal *, +	    doublereal *, doublereal *, doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.5.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       January 2013   +++    ===================================================================== */++++    r__ = *d__ / *c__;+    t = 1. / (*c__ + *d__ * r__);+    *p = dladiv2_(a, b, c__, d__, &r__, &t);+    *a = -(*a);+    *q = dladiv2_(b, a, c__, d__, &r__, &t);++    return 0;++/*     End of DLADIV1 */++} /* dladiv1_ */++doublereal dladiv2_(doublereal *a, doublereal *b, doublereal *c__, doublereal +	*d__, doublereal *r__, doublereal *t)+{+    /* System generated locals */+    doublereal ret_val;++    /* Local variables */+    doublereal br;+++/*  -- LAPACK auxiliary routine (version 3.5.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       January 2013   +++    ===================================================================== */++++    if (*r__ != 0.) {+	br = *b * *r__;+	if (br != 0.) {+	    ret_val = (*a + br) * *t;+	} else {+	    ret_val = *a * *t + *b * *t * *r__;+	}+    } else {+	ret_val = (*a + *d__ * (*b / *c__)) * *t;+    }++    return ret_val;++/*     End of DLADIV12 */++} /* dladiv2_ */+
+ igraph/src/dlae2.c view
@@ -0,0 +1,196 @@+/*  -- 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"++/* > \brief \b DLAE2 computes the eigenvalues of a 2-by-2 symmetric matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAE2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlae2.f+">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlae2.f+">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlae2.f+">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAE2( A, B, C, RT1, RT2 )   ++         DOUBLE PRECISION   A, B, C, RT1, RT2   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION   +   >          The (1,1) element of the 2-by-2 matrix.   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is DOUBLE PRECISION   +   >          The (1,2) and (2,1) elements of the 2-by-2 matrix.   +   > \endverbatim   +   >   +   > \param[in] C   +   > \verbatim   +   >          C is DOUBLE PRECISION   +   >          The (2,2) element of the 2-by-2 matrix.   +   > \endverbatim   +   >   +   > \param[out] RT1   +   > \verbatim   +   >          RT1 is DOUBLE PRECISION   +   >          The eigenvalue of larger absolute value.   +   > \endverbatim   +   >   +   > \param[out] RT2   +   > \verbatim   +   >          RT2 is DOUBLE PRECISION   +   >          The eigenvalue of smaller absolute value.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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.   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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_ */+
+ igraph/src/dlaebz.c view
@@ -0,0 +1,727 @@+/*  -- 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"++/* > \brief \b DLAEBZ computes the number of eigenvalues of a real symmetric tridiagonal matrix which are less+ than or equal to a given value, and performs other tasks required by the routine sstebz.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAEBZ + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaebz.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaebz.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaebz.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAEBZ( IJOB, NITMAX, N, MMAX, MINP, NBMIN, ABSTOL,   +                            RELTOL, PIVMIN, D, E, E2, NVAL, AB, C, MOUT,   +                            NAB, WORK, IWORK, INFO )   ++         INTEGER            IJOB, INFO, MINP, MMAX, MOUT, N, NBMIN, NITMAX   +         DOUBLE PRECISION   ABSTOL, PIVMIN, RELTOL   +         INTEGER            IWORK( * ), NAB( MMAX, * ), NVAL( * )   +         DOUBLE PRECISION   AB( MMAX, * ), C( * ), D( * ), E( * ), E2( * ),   +        $                   WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] IJOB   +   > \verbatim   +   >          IJOB is 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.   +   > \endverbatim   +   >   +   > \param[in] NITMAX   +   > \verbatim   +   >          NITMAX is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The dimension n of the tridiagonal matrix T.  It must be at   +   >          least 1.   +   > \endverbatim   +   >   +   > \param[in] MMAX   +   > \verbatim   +   >          MMAX is INTEGER   +   >          The maximum number of intervals.  If more than MMAX intervals   +   >          are generated, then DLAEBZ will quit with INFO=MMAX+1.   +   > \endverbatim   +   >   +   > \param[in] MINP   +   > \verbatim   +   >          MINP is INTEGER   +   >          The initial number of intervals.  It may not be greater than   +   >          MMAX.   +   > \endverbatim   +   >   +   > \param[in] NBMIN   +   > \verbatim   +   >          NBMIN is INTEGER   +   >          The smallest number of intervals that should be processed   +   >          using a vector loop.  If zero, then only the scalar loop   +   >          will be used.   +   > \endverbatim   +   >   +   > \param[in] ABSTOL   +   > \verbatim   +   >          ABSTOL is 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.   +   > \endverbatim   +   >   +   > \param[in] RELTOL   +   > \verbatim   +   >          RELTOL is 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.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is 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.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] E   +   > \verbatim   +   >          E is DOUBLE PRECISION array, dimension (N)   +   >          The offdiagonal elements of the tridiagonal matrix T in   +   >          positions 1 through N-1.  E(N) is arbitrary.   +   > \endverbatim   +   >   +   > \param[in] E2   +   > \verbatim   +   >          E2 is DOUBLE PRECISION array, dimension (N)   +   >          The squares of the offdiagonal elements of the tridiagonal   +   >          matrix T.  E2(N) is ignored.   +   > \endverbatim   +   >   +   > \param[in,out] NVAL   +   > \verbatim   +   >          NVAL is 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.   +   > \endverbatim   +   >   +   > \param[in,out] AB   +   > \verbatim   +   >          AB is 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.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[out] MOUT   +   > \verbatim   +   >          MOUT is 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.   +   > \endverbatim   +   >   +   > \param[in,out] NAB   +   > \verbatim   +   >          NAB is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MMAX)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (MMAX)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:       All intervals converged.   +   >          = 1--MMAX: The last INFO intervals did not converge.   +   >          = MMAX+1:  More than MMAX intervals were generated.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >      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.   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlaev2.c view
@@ -0,0 +1,249 @@+/*  -- 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"++/* > \brief \b DLAEV2 computes the eigenvalues and eigenvectors of a 2-by-2 symmetric/Hermitian matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAEV2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaev2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaev2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaev2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAEV2( A, B, C, RT1, RT2, CS1, SN1 )   ++         DOUBLE PRECISION   A, B, C, CS1, RT1, RT2, SN1   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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 ].   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION   +   >          The (1,1) element of the 2-by-2 matrix.   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is DOUBLE PRECISION   +   >          The (1,2) element and the conjugate of the (2,1) element of   +   >          the 2-by-2 matrix.   +   > \endverbatim   +   >   +   > \param[in] C   +   > \verbatim   +   >          C is DOUBLE PRECISION   +   >          The (2,2) element of the 2-by-2 matrix.   +   > \endverbatim   +   >   +   > \param[out] RT1   +   > \verbatim   +   >          RT1 is DOUBLE PRECISION   +   >          The eigenvalue of larger absolute value.   +   > \endverbatim   +   >   +   > \param[out] RT2   +   > \verbatim   +   >          RT2 is DOUBLE PRECISION   +   >          The eigenvalue of smaller absolute value.   +   > \endverbatim   +   >   +   > \param[out] CS1   +   > \verbatim   +   >          CS1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] SN1   +   > \verbatim   +   >          SN1 is DOUBLE PRECISION   +   >          The vector (CS1, SN1) is a unit right eigenvector for RT1.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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.   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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_ */+
+ igraph/src/dlaexc.c view
@@ -0,0 +1,524 @@+/*  -- 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;++/* > \brief \b DLAEXC swaps adjacent diagonal blocks of a real upper quasi-triangular matrix in Schur canonica+l form, by an orthogonal similarity transformation.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAEXC + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaexc.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaexc.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaexc.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAEXC( WANTQ, N, T, LDT, Q, LDQ, J1, N1, N2, WORK,   +                            INFO )   ++         LOGICAL            WANTQ   +         INTEGER            INFO, J1, LDQ, LDT, N, N1, N2   +         DOUBLE PRECISION   Q( LDQ, * ), T( LDT, * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] WANTQ   +   > \verbatim   +   >          WANTQ is LOGICAL   +   >          = .TRUE. : accumulate the transformation in the matrix Q;   +   >          = .FALSE.: do not accumulate the transformation.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix T. N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] T   +   > \verbatim   +   >          T is 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.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the array T. LDT >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in,out] Q   +   > \verbatim   +   >          Q is 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.   +   > \endverbatim   +   >   +   > \param[in] LDQ   +   > \verbatim   +   >          LDQ is INTEGER   +   >          The leading dimension of the array Q.   +   >          LDQ >= 1; and if WANTQ is .TRUE., LDQ >= N.   +   > \endverbatim   +   >   +   > \param[in] J1   +   > \verbatim   +   >          J1 is INTEGER   +   >          The index of the first row of the first block T11.   +   > \endverbatim   +   >   +   > \param[in] N1   +   > \verbatim   +   >          N1 is INTEGER   +   >          The order of the first block T11. N1 = 0, 1 or 2.   +   > \endverbatim   +   >   +   > \param[in] N2   +   > \verbatim   +   >          N2 is INTEGER   +   >          The order of the second block T22. N2 = 0, 1 or 2.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlagtf.c view
@@ -0,0 +1,285 @@+/*  -- 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"++/* > \brief \b DLAGTF computes an LU factorization of a matrix T-λI, where T is a general tridiagonal matrix,+ and λ a scalar, using partial pivoting with row interchanges.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAGTF + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlagtf.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlagtf.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlagtf.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAGTF( N, A, LAMBDA, B, C, TOL, D, IN, INFO )   ++         INTEGER            INFO, N   +         DOUBLE PRECISION   LAMBDA, TOL   +         INTEGER            IN( * )   +         DOUBLE PRECISION   A( * ), B( * ), C( * ), D( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix T.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LAMBDA   +   > \verbatim   +   >          LAMBDA is DOUBLE PRECISION   +   >          On entry, the scalar lambda.   +   > \endverbatim   +   >   +   > \param[in,out] B   +   > \verbatim   +   >          B is 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.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] TOL   +   > \verbatim   +   >          TOL is 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.   +   > \endverbatim   +   >   +   > \param[out] D   +   > \verbatim   +   >          D is 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.   +   > \endverbatim   +   >   +   > \param[out] IN   +   > \verbatim   +   >          IN is 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,   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0   : successful exit   +   >          .lt. 0: if INFO = -k, the kth argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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_ */+
+ igraph/src/dlagts.c view
@@ -0,0 +1,415 @@+/*  -- 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"++/* > \brief \b DLAGTS solves the system of equations (T-λI)x = y or (T-λI)Tx = y,where T is a general tridia+gonal matrix and λ a scalar, using the LU factorization computed by slagtf.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAGTS + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlagts.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlagts.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlagts.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAGTS( JOB, N, A, B, C, D, IN, Y, TOL, INFO )   ++         INTEGER            INFO, JOB, N   +         DOUBLE PRECISION   TOL   +         INTEGER            IN( * )   +         DOUBLE PRECISION   A( * ), B( * ), C( * ), D( * ), Y( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOB   +   > \verbatim   +   >          JOB is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix T.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (N)   +   >          On entry, A must contain the diagonal elements of U as   +   >          returned from DLAGTF.   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is DOUBLE PRECISION array, dimension (N-1)   +   >          On entry, B must contain the first super-diagonal elements of   +   >          U as returned from DLAGTF.   +   > \endverbatim   +   >   +   > \param[in] C   +   > \verbatim   +   >          C is DOUBLE PRECISION array, dimension (N-1)   +   >          On entry, C must contain the sub-diagonal elements of L as   +   >          returned from DLAGTF.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N-2)   +   >          On entry, D must contain the second super-diagonal elements   +   >          of U as returned from DLAGTF.   +   > \endverbatim   +   >   +   > \param[in] IN   +   > \verbatim   +   >          IN is INTEGER array, dimension (N)   +   >          On entry, IN must contain details of the matrix P as returned   +   >          from DLAGTF.   +   > \endverbatim   +   >   +   > \param[in,out] Y   +   > \verbatim   +   >          Y is DOUBLE PRECISION array, dimension (N)   +   >          On entry, the right hand side vector y.   +   >          On exit, Y is overwritten by the solution vector x.   +   > \endverbatim   +   >   +   > \param[in,out] TOL   +   > \verbatim   +   >          TOL is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlahqr.c view
@@ -0,0 +1,711 @@+/*  -- 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;++/* > \brief \b DLAHQR computes the eigenvalues and Schur factorization of an upper Hessenberg matrix, using th+e double-shift/single-shift QR algorithm.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAHQR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlahqr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlahqr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlahqr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAHQR( WANTT, WANTZ, N, ILO, IHI, H, LDH, WR, WI,   +                            ILOZ, IHIZ, Z, LDZ, INFO )   ++         INTEGER            IHI, IHIZ, ILO, ILOZ, INFO, LDH, LDZ, N   +         LOGICAL            WANTT, WANTZ   +         DOUBLE PRECISION   H( LDH, * ), WI( * ), WR( * ), Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] WANTT   +   > \verbatim   +   >          WANTT is LOGICAL   +   >          = .TRUE. : the full Schur form T is required;   +   >          = .FALSE.: only eigenvalues are required.   +   > \endverbatim   +   >   +   > \param[in] WANTZ   +   > \verbatim   +   >          WANTZ is LOGICAL   +   >          = .TRUE. : the matrix of Schur vectors Z is required;   +   >          = .FALSE.: Schur vectors are not required.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix H.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[in,out] H   +   > \verbatim   +   >          H is 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.   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is INTEGER   +   >          The leading dimension of the array H. LDH >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] WI   +   > \verbatim   +   >          WI is 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).   +   > \endverbatim   +   >   +   > \param[in] ILOZ   +   > \verbatim   +   >          ILOZ is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHIZ   +   > \verbatim   +   >          IHIZ is INTEGER   +   >          Specify the rows of Z to which transformations must be   +   >          applied if WANTZ is .TRUE..   +   >          1 <= ILOZ <= ILO; IHI <= IHIZ <= N.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >          The leading dimension of the array Z. LDZ >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.)   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >     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).   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =========================================================   +++       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_ */+
+ igraph/src/dlahr2.c view
@@ -0,0 +1,392 @@+/*  -- 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.;++/* > \brief \b DLAHR2 reduces the specified number of first columns of a general rectangular matrix A so that +elements below the specified subdiagonal are zero, and returns auxiliary matrices which are needed to +apply the transformation to the unreduced part   +   of A.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAHR2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlahr2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlahr2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlahr2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAHR2( N, K, NB, A, LDA, TAU, T, LDT, Y, LDY )   ++         INTEGER            K, LDA, LDT, LDY, N, NB   +         DOUBLE PRECISION  A( LDA, * ), T( LDT, NB ), TAU( NB ),   +        $                   Y( LDY, NB )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The offset for the reduction. Elements below the k-th   +   >          subdiagonal in the first NB columns are reduced to zero.   +   >          K < N.   +   > \endverbatim   +   >   +   > \param[in] NB   +   > \verbatim   +   >          NB is INTEGER   +   >          The number of columns to be reduced.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (NB)   +   >          The scalar factors of the elementary reflectors. See Further   +   >          Details.   +   > \endverbatim   +   >   +   > \param[out] T   +   > \verbatim   +   >          T is DOUBLE PRECISION array, dimension (LDT,NB)   +   >          The upper triangular matrix T.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the array T.  LDT >= NB.   +   > \endverbatim   +   >   +   > \param[out] Y   +   > \verbatim   +   >          Y is DOUBLE PRECISION array, dimension (LDY,NB)   +   >          The n-by-nb matrix Y.   +   > \endverbatim   +   >   +   > \param[in] LDY   +   > \verbatim   +   >          LDY is INTEGER   +   >          The leading dimension of the array Y. LDY >= N.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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.)   +   > \endverbatim   ++   > \par 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.   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlaisnan.c view
@@ -0,0 +1,107 @@+/*  -- 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"++/* > \brief \b DLAISNAN tests input for NaN by comparing two arguments for inequality.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAISNAN + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaisna+n.f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaisna+n.f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaisna+n.f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         LOGICAL FUNCTION DLAISNAN( DIN1, DIN2 )   ++         DOUBLE PRECISION   DIN1, DIN2   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] DIN1   +   > \verbatim   +   >          DIN1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] DIN2   +   > \verbatim   +   >          DIN2 is DOUBLE PRECISION   +   >          Two numbers to compare for inequality.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+logical igraphdlaisnan_(doublereal *din1, doublereal *din2)+{+    /* System generated locals */+    logical ret_val;+++/*  -- LAPACK auxiliary routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ===================================================================== */++    ret_val = *din1 != *din2;+    return ret_val;+} /* igraphdlaisnan_ */+
+ igraph/src/dlaln2.c view
@@ -0,0 +1,658 @@+/*  -- 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"++/* > \brief \b DLALN2 solves a 1-by-1 or 2-by-2 linear system of equations of the specified form.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLALN2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaln2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaln2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaln2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLALN2( LTRANS, NA, NW, SMIN, CA, A, LDA, D1, D2, B,   +                            LDB, WR, WI, X, LDX, SCALE, XNORM, INFO )   ++         LOGICAL            LTRANS   +         INTEGER            INFO, LDA, LDB, LDX, NA, NW   +         DOUBLE PRECISION   CA, D1, D2, SCALE, SMIN, WI, WR, XNORM   +         DOUBLE PRECISION   A( LDA, * ), B( LDB, * ), X( LDX, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.)   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] LTRANS   +   > \verbatim   +   >          LTRANS is LOGICAL   +   >          =.TRUE.:  A-transpose will be used.   +   >          =.FALSE.: A will be used (not transposed.)   +   > \endverbatim   +   >   +   > \param[in] NA   +   > \verbatim   +   >          NA is INTEGER   +   >          The size of the matrix A.  It may (only) be 1 or 2.   +   > \endverbatim   +   >   +   > \param[in] NW   +   > \verbatim   +   >          NW is INTEGER   +   >          1 if "w" is real, 2 if "w" is complex.  It may only be 1   +   >          or 2.   +   > \endverbatim   +   >   +   > \param[in] SMIN   +   > \verbatim   +   >          SMIN is 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.)   +   > \endverbatim   +   >   +   > \param[in] CA   +   > \verbatim   +   >          CA is DOUBLE PRECISION   +   >          The coefficient c, which A is multiplied by.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,NA)   +   >          The NA x NA matrix A.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of A.  It must be at least NA.   +   > \endverbatim   +   >   +   > \param[in] D1   +   > \verbatim   +   >          D1 is DOUBLE PRECISION   +   >          The 1,1 element in the diagonal matrix D.   +   > \endverbatim   +   >   +   > \param[in] D2   +   > \verbatim   +   >          D2 is DOUBLE PRECISION   +   >          The 2,2 element in the diagonal matrix D.  Not used if NW=1.   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is 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.   +   > \endverbatim   +   >   +   > \param[in] LDB   +   > \verbatim   +   >          LDB is INTEGER   +   >          The leading dimension of B.  It must be at least NA.   +   > \endverbatim   +   >   +   > \param[in] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION   +   >          The real part of the scalar "w".   +   > \endverbatim   +   >   +   > \param[in] WI   +   > \verbatim   +   >          WI is DOUBLE PRECISION   +   >          The imaginary part of the scalar "w".  Not used if NW=1.   +   > \endverbatim   +   >   +   > \param[out] X   +   > \verbatim   +   >          X is 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.   +   > \endverbatim   +   >   +   > \param[in] LDX   +   > \verbatim   +   >          LDX is INTEGER   +   >          The leading dimension of X.  It must be at least NA.   +   > \endverbatim   +   >   +   > \param[out] SCALE   +   > \verbatim   +   >          SCALE is 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.   +   > \endverbatim   +   >   +   > \param[out] XNORM   +   > \verbatim   +   >          XNORM is DOUBLE PRECISION   +   >          The infinity-norm of X, when X is regarded as an NA x NW   +   >          real matrix.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   ++       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++
+ igraph/src/dlamch.c view
@@ -0,0 +1,204 @@+/*  -- 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.;++/* > \brief \b DLAMCH   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++    Definition:   +    ===========   ++        DOUBLE PRECISION FUNCTION DLAMCH( CMACH )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLAMCH determines double precision machine parameters.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] CMACH   +   > \verbatim   +   >          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)   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+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.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   ++++   =====================================================================   ++++       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_   ++   ***********************************************************************   +   > \brief \b DLAMC3   +   > \details   +   > \b Purpose:   +   > \verbatim   +   > 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.   +   > \endverbatim   +   > \author LAPACK is a software package provided by Univ. of Tennessee, Univ. of California Berkeley, Univ. +of Colorado Denver and NAG Ltd..   +   > \date November 2011   +   > \ingroup auxOTHERauxiliary   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is a DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is a DOUBLE PRECISION   +   >          The values A and B.   +   > \endverbatim   +   > */+doublereal igraphdlamc3_(doublereal *a, doublereal *b)+{+    /* System generated locals */+    doublereal ret_val;+++/*  -- LAPACK auxiliary routine (version 3.4.0) --   +       Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd..   +       November 2010   ++   ===================================================================== */+++    ret_val = *a + *b;++    return ret_val;++/*     End of DLAMC3 */++} /* igraphdlamc3_ */+
+ igraph/src/dlaneg.c view
@@ -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"++/* > \brief \b DLANEG computes the Sturm count.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLANEG + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaneg.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaneg.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaneg.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         INTEGER FUNCTION DLANEG( N, D, LLD, SIGMA, PIVMIN, R )   ++         INTEGER            N, R   +         DOUBLE PRECISION   PIVMIN, SIGMA   +         DOUBLE PRECISION   D( * ), LLD( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.)   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The N diagonal elements of the diagonal matrix D.   +   > \endverbatim   +   >   +   > \param[in] LLD   +   > \verbatim   +   >          LLD is DOUBLE PRECISION array, dimension (N-1)   +   >          The (N-1) elements L(i)*L(i)*D(i).   +   > \endverbatim   +   >   +   > \param[in] SIGMA   +   > \verbatim   +   >          SIGMA is DOUBLE PRECISION   +   >          Shift amount in T - sigma I = L D L^T.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot in the Sturm sequence.  May be used   +   >          when zero pivots are encountered on non-IEEE-754   +   >          architectures.   +   > \endverbatim   +   >   +   > \param[in] R   +   > \verbatim   +   >          R is INTEGER   +   >          The twist index for the twisted factorization that is used   +   >          for the negcount.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   >     Osni Marques, LBNL/NERSC, USA \n   +   >     Christof Voemel, University of California, Berkeley, USA \n   +   >     Jason Riedy, University of California, Berkeley, USA \n   +   >   +    ===================================================================== */+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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   ++       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_ */+
+ igraph/src/dlange.c view
@@ -0,0 +1,254 @@+/*  -- 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;++/* > \brief \b DLANGE returns the value of the 1-norm, Frobenius norm, infinity-norm, or the largest absolute +value of any element of a general rectangular matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLANGE + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlange.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlange.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlange.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         DOUBLE PRECISION FUNCTION DLANGE( NORM, M, N, A, LDA, WORK )   ++         CHARACTER          NORM   +         INTEGER            LDA, M, N   +         DOUBLE PRECISION   A( LDA, * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   +   >   +   > \return DLANGE   +   > \verbatim   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] NORM   +   > \verbatim   +   >          NORM is CHARACTER*1   +   >          Specifies the value to be returned in DLANGE as described   +   >          above.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  M >= 0.  When M = 0,   +   >          DLANGE is set to zero.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  N >= 0.  When N = 0,   +   >          DLANGE is set to zero.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,N)   +   >          The m by n matrix A.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(M,1).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)),   +   >          where LWORK >= M when NORM = 'I'; otherwise, WORK is not   +   >          referenced.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleGEauxiliary   ++    ===================================================================== */+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;++    /* Builtin functions */+    double sqrt(doublereal);++    /* Local variables */+    integer i__, j;+    doublereal sum, temp, scale;+    extern logical igraphlsame_(char *, char *);+    doublereal value = 0.;+    extern logical igraphdisnan_(doublereal *);+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, +	    doublereal *, doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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__) {+		temp = (d__1 = a[i__ + j * a_dim1], abs(d__1));+		if (value < temp || igraphdisnan_(&temp)) {+		    value = temp;+		}+/* 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: */+	    }+	    if (value < sum || igraphdisnan_(&sum)) {+		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__) {+	    temp = work[i__];+	    if (value < temp || igraphdisnan_(&temp)) {+		value = temp;+	    }+/* 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_ */+
+ igraph/src/dlanhs.c view
@@ -0,0 +1,257 @@+/*  -- 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;++/* > \brief \b DLANHS returns the value of the 1-norm, Frobenius norm, infinity-norm, or the largest absolute +value of any element of an upper Hessenberg matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLANHS + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlanhs.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlanhs.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlanhs.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         DOUBLE PRECISION FUNCTION DLANHS( NORM, N, A, LDA, WORK )   ++         CHARACTER          NORM   +         INTEGER            LDA, N   +         DOUBLE PRECISION   A( LDA, * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   +   >   +   > \return DLANHS   +   > \verbatim   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] NORM   +   > \verbatim   +   >          NORM is CHARACTER*1   +   >          Specifies the value to be returned in DLANHS as described   +   >          above.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.  When N = 0, DLANHS is   +   >          set to zero.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(N,1).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)),   +   >          where LWORK >= N when NORM = 'I'; otherwise, WORK is not   +   >          referenced.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    ===================================================================== */+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;++    /* Builtin functions */+    double sqrt(doublereal);++    /* Local variables */+    integer i__, j;+    doublereal sum, scale;+    extern logical igraphlsame_(char *, char *);+    doublereal value = 0.;+    extern logical igraphdisnan_(doublereal *);+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, +	    doublereal *, doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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__) {+		sum = (d__1 = a[i__ + j * a_dim1], abs(d__1));+		if (value < sum || igraphdisnan_(&sum)) {+		    value = sum;+		}+/* 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: */+	    }+	    if (value < sum || igraphdisnan_(&sum)) {+		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__) {+	    sum = work[i__];+	    if (value < sum || igraphdisnan_(&sum)) {+		value = sum;+	    }+/* 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_ */+
+ igraph/src/dlanst.c view
@@ -0,0 +1,215 @@+/*  -- 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;++/* > \brief \b DLANST returns the value of the 1-norm, or the Frobenius norm, or the infinity norm, or the ele+ment of largest absolute value of a real symmetric tridiagonal matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLANST + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlanst.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlanst.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlanst.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         DOUBLE PRECISION FUNCTION DLANST( NORM, N, D, E )   ++         CHARACTER          NORM   +         INTEGER            N   +         DOUBLE PRECISION   D( * ), E( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   +   >   +   > \return DLANST   +   > \verbatim   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] NORM   +   > \verbatim   +   >          NORM is CHARACTER*1   +   >          Specifies the value to be returned in DLANST as described   +   >          above.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.  When N = 0, DLANST is   +   >          set to zero.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The diagonal elements of A.   +   > \endverbatim   +   >   +   > \param[in] E   +   > \verbatim   +   >          E is DOUBLE PRECISION array, dimension (N-1)   +   >          The (n-1) sub-diagonal or super-diagonal elements of A.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+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;++    /* Builtin functions */+    double sqrt(doublereal);++    /* Local variables */+    integer i__;+    doublereal sum, scale;+    extern logical igraphlsame_(char *, char *);+    doublereal anorm = 0.;+    extern logical igraphdisnan_(doublereal *);+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, +	    doublereal *, doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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__) {+	    sum = (d__1 = d__[i__], abs(d__1));+	    if (anorm < sum || igraphdisnan_(&sum)) {+		anorm = sum;+	    }+	    sum = (d__1 = e[i__], abs(d__1));+	    if (anorm < sum || igraphdisnan_(&sum)) {+		anorm = sum;+	    }+/* L10: */+	}+    } else if (igraphlsame_(norm, "O") || *(unsigned char *)+	    norm == '1' || igraphlsame_(norm, "I")) {++/*        Find norm1(A). */++	if (*n == 1) {+	    anorm = abs(d__[1]);+	} else {+	    anorm = abs(d__[1]) + abs(e[1]);+	    sum = (d__1 = e[*n - 1], abs(d__1)) + (d__2 = d__[*n], abs(d__2));+	    if (anorm < sum || igraphdisnan_(&sum)) {+		anorm = sum;+	    }+	    i__1 = *n - 1;+	    for (i__ = 2; i__ <= i__1; ++i__) {+		sum = (d__1 = d__[i__], abs(d__1)) + (d__2 = e[i__], abs(d__2)+			) + (d__3 = e[i__ - 1], abs(d__3));+		if (anorm < sum || igraphdisnan_(&sum)) {+		    anorm = sum;+		}+/* 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_ */+
+ igraph/src/dlansy.c view
@@ -0,0 +1,293 @@+/*  -- 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;++/* > \brief \b DLANSY returns the value of the 1-norm, or the Frobenius norm, or the infinity norm, or the ele+ment of largest absolute value of a real symmetric matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLANSY + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlansy.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlansy.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlansy.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         DOUBLE PRECISION FUNCTION DLANSY( NORM, UPLO, N, A, LDA, WORK )   ++         CHARACTER          NORM, UPLO   +         INTEGER            LDA, N   +         DOUBLE PRECISION   A( LDA, * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   +   >   +   > \return DLANSY   +   > \verbatim   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] NORM   +   > \verbatim   +   >          NORM is CHARACTER*1   +   >          Specifies the value to be returned in DLANSY as described   +   >          above.   +   > \endverbatim   +   >   +   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is 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   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.  When N = 0, DLANSY is   +   >          set to zero.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(N,1).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK)),   +   >          where LWORK >= N when NORM = 'I' or '1' or 'O'; otherwise,   +   >          WORK is not referenced.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleSYauxiliary   ++    ===================================================================== */+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;++    /* Builtin functions */+    double sqrt(doublereal);++    /* Local variables */+    integer i__, j;+    doublereal sum, absa, scale;+    extern logical igraphlsame_(char *, char *);+    doublereal value = 0.;+    extern logical igraphdisnan_(doublereal *);+    extern /* Subroutine */ int igraphdlassq_(integer *, doublereal *, integer *, +	    doublereal *, doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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__) {+		    sum = (d__1 = a[i__ + j * a_dim1], abs(d__1));+		    if (value < sum || igraphdisnan_(&sum)) {+			value = sum;+		    }+/* L10: */+		}+/* L20: */+	    }+	} else {+	    i__1 = *n;+	    for (j = 1; j <= i__1; ++j) {+		i__2 = *n;+		for (i__ = j; i__ <= i__2; ++i__) {+		    sum = (d__1 = a[i__ + j * a_dim1], abs(d__1));+		    if (value < sum || igraphdisnan_(&sum)) {+			value = sum;+		    }+/* 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__) {+		sum = work[i__];+		if (value < sum || igraphdisnan_(&sum)) {+		    value = sum;+		}+/* 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: */+		}+		if (value < sum || igraphdisnan_(&sum)) {+		    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_ */+
+ igraph/src/dlanv2.c view
@@ -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.;++/* > \brief \b DLANV2 computes the Schur factorization of a real 2-by-2 nonsymmetric matrix in standard form. +  ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLANV2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlanv2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlanv2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlanv2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLANV2( A, B, C, D, RT1R, RT1I, RT2R, RT2I, CS, SN )   ++         DOUBLE PRECISION   A, B, C, CS, D, RT1I, RT1R, RT2I, RT2R, SN   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in,out] A   +   > \verbatim   +   >          A is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] B   +   > \verbatim   +   >          B is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] D   +   > \verbatim   +   >          D is DOUBLE PRECISION   +   >          On entry, the elements of the input matrix.   +   >          On exit, they are overwritten by the elements of the   +   >          standardised Schur form.   +   > \endverbatim   +   >   +   > \param[out] RT1R   +   > \verbatim   +   >          RT1R is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] RT1I   +   > \verbatim   +   >          RT1I is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] RT2R   +   > \verbatim   +   >          RT2R is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] RT2I   +   > \verbatim   +   >          RT2I is DOUBLE PRECISION   +   >          The real and imaginary parts of the eigenvalues. If the   +   >          eigenvalues are a complex conjugate pair, RT1I > 0.   +   > \endverbatim   +   >   +   > \param[out] CS   +   > \verbatim   +   >          CS is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] SN   +   > \verbatim   +   >          SN is DOUBLE PRECISION   +   >          Parameters of the rotation matrix.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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).   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ===================================================================== */+++    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_ */+
+ igraph/src/dlapy2.c view
@@ -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"++/* > \brief \b DLAPY2 returns sqrt(x2+y2).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAPY2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlapy2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlapy2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlapy2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         DOUBLE PRECISION FUNCTION DLAPY2( X, Y )   ++         DOUBLE PRECISION   X, Y   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLAPY2 returns sqrt(x**2+y**2), taking care not to cause unnecessary   +   > overflow.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] X   +   > \verbatim   +   >          X is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] Y   +   > \verbatim   +   >          Y is DOUBLE PRECISION   +   >          X and Y specify the values x and y.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ===================================================================== */+++    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_ */+
+ igraph/src/dlaqr0.c view
@@ -0,0 +1,849 @@+/*  -- 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;++/* > \brief \b DLAQR0 computes the eigenvalues of a Hessenberg matrix, and optionally the matrices from the Sc+hur decomposition.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAQR0 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaqr0.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaqr0.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaqr0.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAQR0( WANTT, WANTZ, N, ILO, IHI, H, LDH, WR, WI,   +                            ILOZ, IHIZ, Z, LDZ, WORK, LWORK, INFO )   ++         INTEGER            IHI, IHIZ, ILO, ILOZ, INFO, LDH, LDZ, LWORK, N   +         LOGICAL            WANTT, WANTZ   +         DOUBLE PRECISION   H( LDH, * ), WI( * ), WORK( * ), WR( * ),   +        $                   Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] WANTT   +   > \verbatim   +   >          WANTT is LOGICAL   +   >          = .TRUE. : the full Schur form T is required;   +   >          = .FALSE.: only eigenvalues are required.   +   > \endverbatim   +   >   +   > \param[in] WANTZ   +   > \verbatim   +   >          WANTZ is LOGICAL   +   >          = .TRUE. : the matrix of Schur vectors Z is required;   +   >          = .FALSE.: Schur vectors are not required.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >           The order of the matrix H.  N .GE. 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[in,out] H   +   > \verbatim   +   >          H is 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.   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is INTEGER   +   >           The leading dimension of the array H. LDH .GE. max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION array, dimension (IHI)   +   > \endverbatim   +   >   +   > \param[out] WI   +   > \verbatim   +   >          WI is 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).   +   > \endverbatim   +   >   +   > \param[in] ILOZ   +   > \verbatim   +   >          ILOZ is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHIZ   +   > \verbatim   +   >          IHIZ is 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.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.)   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >           The leading dimension of the array Z.  if WANTZ is .TRUE.   +   >           then LDZ.GE.MAX(1,IHIZ).  Otherwize, LDZ.GE.1.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension LWORK   +   >           On exit, if LWORK = -1, WORK(1) returns an estimate of   +   >           the optimal value for LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++   > \par Contributors:   +    ==================   +   >   +   >       Karen Braman and Ralph Byers, Department of Mathematics,   +   >       University of Kansas, USA   ++   > \par 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.   +   > \n   +   >       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.   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ================================================================   +++       ==== 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_ */+
+ igraph/src/dlaqr1.c view
@@ -0,0 +1,198 @@+/*  -- 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"++/* > \brief \b DLAQR1 sets a scalar multiple of the first column of the product of 2-by-2 or 3-by-3 matrix H a+nd specified shifts.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAQR1 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaqr1.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaqr1.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaqr1.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAQR1( N, H, LDH, SR1, SI1, SR2, SI2, V )   ++         DOUBLE PRECISION   SI1, SI2, SR1, SR2   +         INTEGER            LDH, N   +         DOUBLE PRECISION   H( LDH, * ), V( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >      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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is integer   +   >              Order of the matrix H. N must be either 2 or 3.   +   > \endverbatim   +   >   +   > \param[in] H   +   > \verbatim   +   >          H is DOUBLE PRECISION array of dimension (LDH,N)   +   >              The 2-by-2 or 3-by-3 matrix H in (*).   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is integer   +   >              The leading dimension of H as declared in   +   >              the calling procedure.  LDH.GE.N   +   > \endverbatim   +   >   +   > \param[in] SR1   +   > \verbatim   +   >          SR1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] SI1   +   > \verbatim   +   >          SI1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] SR2   +   > \verbatim   +   >          SR2 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] SI2   +   > \verbatim   +   >          SI2 is DOUBLE PRECISION   +   >              The shifts in (*).   +   > \endverbatim   +   >   +   > \param[out] V   +   > \verbatim   +   >          V is DOUBLE PRECISION array of dimension N   +   >              A scalar multiple of the first column of the   +   >              matrix K in (*).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   >       Karen Braman and Ralph Byers, Department of Mathematics,   +   >       University of Kansas, USA   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ================================================================   ++       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_ */+
+ igraph/src/dlaqr2.c view
@@ -0,0 +1,821 @@+/*  -- 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_;++/* > \brief \b DLAQR2 performs the orthogonal similarity transformation of a Hessenberg matrix to detect and d+eflate fully converged eigenvalues from a trailing principal submatrix (aggressive early deflation). +  ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAQR2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaqr2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaqr2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaqr2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAQR2( WANTT, WANTZ, N, KTOP, KBOT, NW, H, LDH, ILOZ,   +                            IHIZ, Z, LDZ, NS, ND, SR, SI, V, LDV, NH, T,   +                            LDT, NV, WV, LDWV, WORK, LWORK )   ++         INTEGER            IHIZ, ILOZ, KBOT, KTOP, LDH, LDT, LDV, LDWV,   +        $                   LDZ, LWORK, N, ND, NH, NS, NV, NW   +         LOGICAL            WANTT, WANTZ   +         DOUBLE PRECISION   H( LDH, * ), SI( * ), SR( * ), T( LDT, * ),   +        $                   V( LDV, * ), WORK( * ), WV( LDWV, * ),   +        $                   Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >    DLAQR2 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] WANTT   +   > \verbatim   +   >          WANTT is 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.   +   > \endverbatim   +   >   +   > \param[in] WANTZ   +   > \verbatim   +   >          WANTZ is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix H and (if WANTZ is .TRUE.) the   +   >          order of the orthogonal matrix Z.   +   > \endverbatim   +   >   +   > \param[in] KTOP   +   > \verbatim   +   >          KTOP is 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.   +   > \endverbatim   +   >   +   > \param[in] KBOT   +   > \verbatim   +   >          KBOT is 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.   +   > \endverbatim   +   >   +   > \param[in] NW   +   > \verbatim   +   >          NW is INTEGER   +   >          Deflation window size.  1 .LE. NW .LE. (KBOT-KTOP+1).   +   > \endverbatim   +   >   +   > \param[in,out] H   +   > \verbatim   +   >          H is 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.   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is integer   +   >          Leading dimension of H just as declared in the calling   +   >          subroutine.  N .LE. LDH   +   > \endverbatim   +   >   +   > \param[in] ILOZ   +   > \verbatim   +   >          ILOZ is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHIZ   +   > \verbatim   +   >          IHIZ is INTEGER   +   >          Specify the rows of Z to which transformations must be   +   >          applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is integer   +   >          The leading dimension of Z just as declared in the   +   >          calling subroutine.  1 .LE. LDZ.   +   > \endverbatim   +   >   +   > \param[out] NS   +   > \verbatim   +   >          NS is integer   +   >          The number of unconverged (ie approximate) eigenvalues   +   >          returned in SR and SI that may be used as shifts by the   +   >          calling subroutine.   +   > \endverbatim   +   >   +   > \param[out] ND   +   > \verbatim   +   >          ND is integer   +   >          The number of converged eigenvalues uncovered by this   +   >          subroutine.   +   > \endverbatim   +   >   +   > \param[out] SR   +   > \verbatim   +   >          SR is DOUBLE PRECISION array, dimension (KBOT)   +   > \endverbatim   +   >   +   > \param[out] SI   +   > \verbatim   +   >          SI is 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.   +   > \endverbatim   +   >   +   > \param[out] V   +   > \verbatim   +   >          V is DOUBLE PRECISION array, dimension (LDV,NW)   +   >          An NW-by-NW work array.   +   > \endverbatim   +   >   +   > \param[in] LDV   +   > \verbatim   +   >          LDV is integer scalar   +   >          The leading dimension of V just as declared in the   +   >          calling subroutine.  NW .LE. LDV   +   > \endverbatim   +   >   +   > \param[in] NH   +   > \verbatim   +   >          NH is integer scalar   +   >          The number of columns of T.  NH.GE.NW.   +   > \endverbatim   +   >   +   > \param[out] T   +   > \verbatim   +   >          T is DOUBLE PRECISION array, dimension (LDT,NW)   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is integer   +   >          The leading dimension of T just as declared in the   +   >          calling subroutine.  NW .LE. LDT   +   > \endverbatim   +   >   +   > \param[in] NV   +   > \verbatim   +   >          NV is integer   +   >          The number of rows of work array WV available for   +   >          workspace.  NV.GE.NW.   +   > \endverbatim   +   >   +   > \param[out] WV   +   > \verbatim   +   >          WV is DOUBLE PRECISION array, dimension (LDWV,NW)   +   > \endverbatim   +   >   +   > \param[in] LDWV   +   > \verbatim   +   >          LDWV is integer   +   >          The leading dimension of W just as declared in the   +   >          calling subroutine.  NW .LE. LDV   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is 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.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   >       Karen Braman and Ralph Byers, Department of Mathematics,   +   >       University of Kansas, USA   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ================================================================   ++       ==== 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_ */+
+ igraph/src/dlaqr3.c view
@@ -0,0 +1,840 @@+/*  -- 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;++/* > \brief \b DLAQR3 performs the orthogonal similarity transformation of a Hessenberg matrix to detect and d+eflate fully converged eigenvalues from a trailing principal submatrix (aggressive early deflation). +  ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAQR3 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaqr3.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaqr3.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaqr3.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAQR3( WANTT, WANTZ, N, KTOP, KBOT, NW, H, LDH, ILOZ,   +                            IHIZ, Z, LDZ, NS, ND, SR, SI, V, LDV, NH, T,   +                            LDT, NV, WV, LDWV, WORK, LWORK )   ++         INTEGER            IHIZ, ILOZ, KBOT, KTOP, LDH, LDT, LDV, LDWV,   +        $                   LDZ, LWORK, N, ND, NH, NS, NV, NW   +         LOGICAL            WANTT, WANTZ   +         DOUBLE PRECISION   H( LDH, * ), SI( * ), SR( * ), T( LDT, * ),   +        $                   V( LDV, * ), WORK( * ), WV( LDWV, * ),   +        $                   Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >    Aggressive early deflation:   +   >   +   >    DLAQR3 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] WANTT   +   > \verbatim   +   >          WANTT is 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.   +   > \endverbatim   +   >   +   > \param[in] WANTZ   +   > \verbatim   +   >          WANTZ is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix H and (if WANTZ is .TRUE.) the   +   >          order of the orthogonal matrix Z.   +   > \endverbatim   +   >   +   > \param[in] KTOP   +   > \verbatim   +   >          KTOP is 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.   +   > \endverbatim   +   >   +   > \param[in] KBOT   +   > \verbatim   +   >          KBOT is 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.   +   > \endverbatim   +   >   +   > \param[in] NW   +   > \verbatim   +   >          NW is INTEGER   +   >          Deflation window size.  1 .LE. NW .LE. (KBOT-KTOP+1).   +   > \endverbatim   +   >   +   > \param[in,out] H   +   > \verbatim   +   >          H is 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.   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is integer   +   >          Leading dimension of H just as declared in the calling   +   >          subroutine.  N .LE. LDH   +   > \endverbatim   +   >   +   > \param[in] ILOZ   +   > \verbatim   +   >          ILOZ is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHIZ   +   > \verbatim   +   >          IHIZ is INTEGER   +   >          Specify the rows of Z to which transformations must be   +   >          applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is integer   +   >          The leading dimension of Z just as declared in the   +   >          calling subroutine.  1 .LE. LDZ.   +   > \endverbatim   +   >   +   > \param[out] NS   +   > \verbatim   +   >          NS is integer   +   >          The number of unconverged (ie approximate) eigenvalues   +   >          returned in SR and SI that may be used as shifts by the   +   >          calling subroutine.   +   > \endverbatim   +   >   +   > \param[out] ND   +   > \verbatim   +   >          ND is integer   +   >          The number of converged eigenvalues uncovered by this   +   >          subroutine.   +   > \endverbatim   +   >   +   > \param[out] SR   +   > \verbatim   +   >          SR is DOUBLE PRECISION array, dimension (KBOT)   +   > \endverbatim   +   >   +   > \param[out] SI   +   > \verbatim   +   >          SI is 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.   +   > \endverbatim   +   >   +   > \param[out] V   +   > \verbatim   +   >          V is DOUBLE PRECISION array, dimension (LDV,NW)   +   >          An NW-by-NW work array.   +   > \endverbatim   +   >   +   > \param[in] LDV   +   > \verbatim   +   >          LDV is integer scalar   +   >          The leading dimension of V just as declared in the   +   >          calling subroutine.  NW .LE. LDV   +   > \endverbatim   +   >   +   > \param[in] NH   +   > \verbatim   +   >          NH is integer scalar   +   >          The number of columns of T.  NH.GE.NW.   +   > \endverbatim   +   >   +   > \param[out] T   +   > \verbatim   +   >          T is DOUBLE PRECISION array, dimension (LDT,NW)   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is integer   +   >          The leading dimension of T just as declared in the   +   >          calling subroutine.  NW .LE. LDT   +   > \endverbatim   +   >   +   > \param[in] NV   +   > \verbatim   +   >          NV is integer   +   >          The number of rows of work array WV available for   +   >          workspace.  NV.GE.NW.   +   > \endverbatim   +   >   +   > \param[out] WV   +   > \verbatim   +   >          WV is DOUBLE PRECISION array, dimension (LDWV,NW)   +   > \endverbatim   +   >   +   > \param[in] LDWV   +   > \verbatim   +   >          LDWV is integer   +   >          The leading dimension of W just as declared in the   +   >          calling subroutine.  NW .LE. LDV   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is 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.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   >       Karen Braman and Ralph Byers, Department of Mathematics,   +   >       University of Kansas, USA   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ================================================================   ++       ==== 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_ */+
+ igraph/src/dlaqr4.c view
@@ -0,0 +1,844 @@+/*  -- 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;++/* > \brief \b DLAQR4 computes the eigenvalues of a Hessenberg matrix, and optionally the matrices from the Sc+hur decomposition.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAQR4 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaqr4.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaqr4.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaqr4.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAQR4( WANTT, WANTZ, N, ILO, IHI, H, LDH, WR, WI,   +                            ILOZ, IHIZ, Z, LDZ, WORK, LWORK, INFO )   ++         INTEGER            IHI, IHIZ, ILO, ILOZ, INFO, LDH, LDZ, LWORK, N   +         LOGICAL            WANTT, WANTZ   +         DOUBLE PRECISION   H( LDH, * ), WI( * ), WORK( * ), WR( * ),   +        $                   Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >    DLAQR4 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.   +   >   +   >    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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] WANTT   +   > \verbatim   +   >          WANTT is LOGICAL   +   >          = .TRUE. : the full Schur form T is required;   +   >          = .FALSE.: only eigenvalues are required.   +   > \endverbatim   +   >   +   > \param[in] WANTZ   +   > \verbatim   +   >          WANTZ is LOGICAL   +   >          = .TRUE. : the matrix of Schur vectors Z is required;   +   >          = .FALSE.: Schur vectors are not required.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >           The order of the matrix H.  N .GE. 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[in,out] H   +   > \verbatim   +   >          H is 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.   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is INTEGER   +   >           The leading dimension of the array H. LDH .GE. max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION array, dimension (IHI)   +   > \endverbatim   +   >   +   > \param[out] WI   +   > \verbatim   +   >          WI is 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).   +   > \endverbatim   +   >   +   > \param[in] ILOZ   +   > \verbatim   +   >          ILOZ is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHIZ   +   > \verbatim   +   >          IHIZ is 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.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.)   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >           The leading dimension of the array Z.  if WANTZ is .TRUE.   +   >           then LDZ.GE.MAX(1,IHIZ).  Otherwize, LDZ.GE.1.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension LWORK   +   >           On exit, if LWORK = -1, WORK(1) returns an estimate of   +   >           the optimal value for LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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 a orthogonal 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(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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   >       Karen Braman and Ralph Byers, Department of Mathematics,   +   >       University of Kansas, USA   ++   > \par 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.   +   > \n   +   >       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.   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ================================================================   ++       ==== 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_ */+
+ igraph/src/dlaqr5.c view
@@ -0,0 +1,1148 @@+/*  -- 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;++/* > \brief \b DLAQR5 performs a single small-bulge multi-shift QR sweep.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAQR5 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaqr5.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaqr5.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaqr5.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAQR5( WANTT, WANTZ, KACC22, N, KTOP, KBOT, NSHFTS,   +                            SR, SI, H, LDH, ILOZ, IHIZ, Z, LDZ, V, LDV, U,   +                            LDU, NV, WV, LDWV, NH, WH, LDWH )   ++         INTEGER            IHIZ, ILOZ, KACC22, KBOT, KTOP, LDH, LDU, LDV,   +        $                   LDWH, LDWV, LDZ, N, NH, NSHFTS, NV   +         LOGICAL            WANTT, WANTZ   +         DOUBLE PRECISION   H( LDH, * ), SI( * ), SR( * ), U( LDU, * ),   +        $                   V( LDV, * ), WH( LDWH, * ), WV( LDWV, * ),   +        $                   Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >    DLAQR5, called by DLAQR0, performs a   +   >    single small-bulge multi-shift QR sweep.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] WANTT   +   > \verbatim   +   >          WANTT is logical scalar   +   >             WANTT = .true. if the quasi-triangular Schur factor   +   >             is being computed.  WANTT is set to .false. otherwise.   +   > \endverbatim   +   >   +   > \param[in] WANTZ   +   > \verbatim   +   >          WANTZ is logical scalar   +   >             WANTZ = .true. if the orthogonal Schur factor is being   +   >             computed.  WANTZ is set to .false. otherwise.   +   > \endverbatim   +   >   +   > \param[in] KACC22   +   > \verbatim   +   >          KACC22 is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is integer scalar   +   >             N is the order of the Hessenberg matrix H upon which this   +   >             subroutine operates.   +   > \endverbatim   +   >   +   > \param[in] KTOP   +   > \verbatim   +   >          KTOP is integer scalar   +   > \endverbatim   +   >   +   > \param[in] KBOT   +   > \verbatim   +   >          KBOT is 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.   +   > \endverbatim   +   >   +   > \param[in] NSHFTS   +   > \verbatim   +   >          NSHFTS is integer scalar   +   >             NSHFTS gives the number of simultaneous shifts.  NSHFTS   +   >             must be positive and even.   +   > \endverbatim   +   >   +   > \param[in,out] SR   +   > \verbatim   +   >          SR is DOUBLE PRECISION array of size (NSHFTS)   +   > \endverbatim   +   >   +   > \param[in,out] SI   +   > \verbatim   +   >          SI is 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.   +   > \endverbatim   +   >   +   > \param[in,out] H   +   > \verbatim   +   >          H is 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.   +   > \endverbatim   +   >   +   > \param[in] LDH   +   > \verbatim   +   >          LDH is integer scalar   +   >             LDH is the leading dimension of H just as declared in the   +   >             calling procedure.  LDH.GE.MAX(1,N).   +   > \endverbatim   +   >   +   > \param[in] ILOZ   +   > \verbatim   +   >          ILOZ is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHIZ   +   > \verbatim   +   >          IHIZ is INTEGER   +   >             Specify the rows of Z to which transformations must be   +   >             applied if WANTZ is .TRUE.. 1 .LE. ILOZ .LE. IHIZ .LE. N   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is integer scalar   +   >             LDA is the leading dimension of Z just as declared in   +   >             the calling procedure. LDZ.GE.N.   +   > \endverbatim   +   >   +   > \param[out] V   +   > \verbatim   +   >          V is DOUBLE PRECISION array of size (LDV,NSHFTS/2)   +   > \endverbatim   +   >   +   > \param[in] LDV   +   > \verbatim   +   >          LDV is integer scalar   +   >             LDV is the leading dimension of V as declared in the   +   >             calling procedure.  LDV.GE.3.   +   > \endverbatim   +   >   +   > \param[out] U   +   > \verbatim   +   >          U is DOUBLE PRECISION array of size   +   >             (LDU,3*NSHFTS-3)   +   > \endverbatim   +   >   +   > \param[in] LDU   +   > \verbatim   +   >          LDU is integer scalar   +   >             LDU is the leading dimension of U just as declared in the   +   >             in the calling subroutine.  LDU.GE.3*NSHFTS-3.   +   > \endverbatim   +   >   +   > \param[in] NH   +   > \verbatim   +   >          NH is integer scalar   +   >             NH is the number of columns in array WH available for   +   >             workspace. NH.GE.1.   +   > \endverbatim   +   >   +   > \param[out] WH   +   > \verbatim   +   >          WH is DOUBLE PRECISION array of size (LDWH,NH)   +   > \endverbatim   +   >   +   > \param[in] LDWH   +   > \verbatim   +   >          LDWH is integer scalar   +   >             Leading dimension of WH just as declared in the   +   >             calling procedure.  LDWH.GE.3*NSHFTS-3.   +   > \endverbatim   +   >   +   > \param[in] NV   +   > \verbatim   +   >          NV is integer scalar   +   >             NV is the number of rows in WV agailable for workspace.   +   >             NV.GE.1.   +   > \endverbatim   +   >   +   > \param[out] WV   +   > \verbatim   +   >          WV is DOUBLE PRECISION array of size   +   >             (LDWV,3*NSHFTS-3)   +   > \endverbatim   +   >   +   > \param[in] LDWV   +   > \verbatim   +   >          LDWV is integer scalar   +   >             LDWV is the leading dimension of WV as declared in the   +   >             in the calling subroutine.  LDWV.GE.NV.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   >       Karen Braman and Ralph Byers, Department of Mathematics,   +   >       University of Kansas, USA   ++   > \par 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.   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    ================================================================   +++       ==== 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_ */+
+ igraph/src/dlaqrb.c view
@@ -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_ */+
+ igraph/src/dlaqtr.c view
@@ -0,0 +1,898 @@+/*  -- 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_;++/* > \brief \b DLAQTR solves a real quasi-triangular system of equations, or a complex quasi-triangular system+ of special form, in real arithmetic.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAQTR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaqtr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaqtr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaqtr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAQTR( LTRAN, LREAL, N, T, LDT, B, W, SCALE, X, WORK,   +                            INFO )   ++         LOGICAL            LREAL, LTRAN   +         INTEGER            INFO, LDT, N   +         DOUBLE PRECISION   SCALE, W   +         DOUBLE PRECISION   B( * ), T( LDT, * ), WORK( * ), X( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] LTRAN   +   > \verbatim   +   >          LTRAN is 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.   +   > \endverbatim   +   >   +   > \param[in] LREAL   +   > \verbatim   +   >          LREAL is LOGICAL   +   >          On entry, LREAL specifies the input matrix structure:   +   >             = .FALSE.,    the input is complex   +   >             = .TRUE.,     the input is real   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          On entry, N specifies the order of T+i*B. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] T   +   > \verbatim   +   >          T is 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.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the matrix T. LDT >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is 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.   +   > \endverbatim   +   >   +   > \param[in] W   +   > \verbatim   +   >          W is DOUBLE PRECISION   +   >          On entry, W is the diagonal element of the matrix B.   +   >          If LREAL = .TRUE., W is not referenced.   +   > \endverbatim   +   >   +   > \param[out] SCALE   +   > \verbatim   +   >          SCALE is DOUBLE PRECISION   +   >          On exit, SCALE is the scale factor.   +   > \endverbatim   +   >   +   > \param[in,out] X   +   > \verbatim   +   >          X is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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_ */+
+ igraph/src/dlar1v.c view
@@ -0,0 +1,545 @@+/*  -- 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"++/* > \brief \b DLAR1V computes the (scaled) r-th column of the inverse of the submatrix in rows b1 through bn +of the tridiagonal matrix LDLT - λI.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLAR1V + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlar1v.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlar1v.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlar1v.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLAR1V( N, B1, BN, LAMBDA, D, L, LD, LLD,   +                    PIVMIN, GAPTOL, Z, WANTNC, NEGCNT, ZTZ, MINGMA,   +                    R, ISUPPZ, NRMINV, RESID, RQCORR, WORK )   ++         LOGICAL            WANTNC   +         INTEGER   B1, BN, N, NEGCNT, R   +         DOUBLE PRECISION   GAPTOL, LAMBDA, MINGMA, NRMINV, PIVMIN, RESID,   +        $                   RQCORR, ZTZ   +         INTEGER            ISUPPZ( * )   +         DOUBLE PRECISION   D( * ), L( * ), LD( * ), LLD( * ),   +        $                  WORK( * )   +         DOUBLE PRECISION Z( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >           The order of the matrix L D L**T.   +   > \endverbatim   +   >   +   > \param[in] B1   +   > \verbatim   +   >          B1 is INTEGER   +   >           First index of the submatrix of L D L**T.   +   > \endverbatim   +   >   +   > \param[in] BN   +   > \verbatim   +   >          BN is INTEGER   +   >           Last index of the submatrix of L D L**T.   +   > \endverbatim   +   >   +   > \param[in] LAMBDA   +   > \verbatim   +   >          LAMBDA is 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.   +   > \endverbatim   +   >   +   > \param[in] L   +   > \verbatim   +   >          L is DOUBLE PRECISION array, dimension (N-1)   +   >           The (n-1) subdiagonal elements of the unit bidiagonal matrix   +   >           L, in elements 1 to N-1.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >           The n diagonal elements of the diagonal matrix D.   +   > \endverbatim   +   >   +   > \param[in] LD   +   > \verbatim   +   >          LD is DOUBLE PRECISION array, dimension (N-1)   +   >           The n-1 elements L(i)*D(i).   +   > \endverbatim   +   >   +   > \param[in] LLD   +   > \verbatim   +   >          LLD is DOUBLE PRECISION array, dimension (N-1)   +   >           The n-1 elements L(i)*L(i)*D(i).   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >           The minimum pivot in the Sturm sequence.   +   > \endverbatim   +   >   +   > \param[in] GAPTOL   +   > \verbatim   +   >          GAPTOL is DOUBLE PRECISION   +   >           Tolerance that indicates when eigenvector entries are negligible   +   >           w.r.t. their contribution to the residual.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] WANTNC   +   > \verbatim   +   >          WANTNC is LOGICAL   +   >           Specifies whether NEGCNT has to be computed.   +   > \endverbatim   +   >   +   > \param[out] NEGCNT   +   > \verbatim   +   >          NEGCNT is INTEGER   +   >           If WANTNC is .TRUE. then NEGCNT = the number of pivots < pivmin   +   >           in the  matrix factorization L D L**T, and NEGCNT = -1 otherwise.   +   > \endverbatim   +   >   +   > \param[out] ZTZ   +   > \verbatim   +   >          ZTZ is DOUBLE PRECISION   +   >           The square of the 2-norm of Z.   +   > \endverbatim   +   >   +   > \param[out] MINGMA   +   > \verbatim   +   >          MINGMA is DOUBLE PRECISION   +   >           The reciprocal of the largest (in magnitude) diagonal   +   >           element of the inverse of L D L**T - sigma I.   +   > \endverbatim   +   >   +   > \param[in,out] R   +   > \verbatim   +   >          R is 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.   +   > \endverbatim   +   >   +   > \param[out] ISUPPZ   +   > \verbatim   +   >          ISUPPZ is 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 ).   +   > \endverbatim   +   >   +   > \param[out] NRMINV   +   > \verbatim   +   >          NRMINV is DOUBLE PRECISION   +   >           NRMINV = 1/SQRT( ZTZ )   +   > \endverbatim   +   >   +   > \param[out] RESID   +   > \verbatim   +   >          RESID is DOUBLE PRECISION   +   >           The residual of the FP vector.   +   >           RESID = ABS( MINGMA )/SQRT( ZTZ )   +   > \endverbatim   +   >   +   > \param[out] RQCORR   +   > \verbatim   +   >          RQCORR is DOUBLE PRECISION   +   >           The Rayleigh Quotient correction to LAMBDA.   +   >           RQCORR = MINGMA*TMP   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (4*N)   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarf.c view
@@ -0,0 +1,255 @@+/*  -- 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;++/* > \brief \b DLARF applies an elementary reflector to a general rectangular matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARF + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarf.f+">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarf.f+">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarf.f+">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARF( SIDE, M, N, V, INCV, TAU, C, LDC, WORK )   ++         CHARACTER          SIDE   +         INTEGER            INCV, LDC, M, N   +         DOUBLE PRECISION   TAU   +         DOUBLE PRECISION   C( LDC, * ), V( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': form  H * C   +   >          = 'R': form  C * H   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C.   +   > \endverbatim   +   >   +   > \param[in] V   +   > \verbatim   +   >          V is 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.   +   > \endverbatim   +   >   +   > \param[in] INCV   +   > \verbatim   +   >          INCV is INTEGER   +   >          The increment between elements of v. INCV <> 0.   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION   +   >          The value tau in the representation of H.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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'.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension   +   >                         (N) if SIDE = 'L'   +   >                      or (M) if SIDE = 'R'   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarfb.c view
@@ -0,0 +1,838 @@+/*  -- 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.;++/* > \brief \b DLARFB applies a block reflector or its transpose to a general rectangular matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARFB + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarfb.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarfb.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarfb.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARFB( SIDE, TRANS, DIRECT, STOREV, M, N, K, V, LDV,   +                            T, LDT, C, LDC, WORK, LDWORK )   ++         CHARACTER          DIRECT, SIDE, STOREV, TRANS   +         INTEGER            K, LDC, LDT, LDV, LDWORK, M, N   +         DOUBLE PRECISION   C( LDC, * ), T( LDT, * ), V( LDV, * ),   +        $                   WORK( LDWORK, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': apply H or H**T from the Left   +   >          = 'R': apply H or H**T from the Right   +   > \endverbatim   +   >   +   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is CHARACTER*1   +   >          = 'N': apply H (No transpose)   +   >          = 'T': apply H**T (Transpose)   +   > \endverbatim   +   >   +   > \param[in] DIRECT   +   > \verbatim   +   >          DIRECT is 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)   +   > \endverbatim   +   >   +   > \param[in] STOREV   +   > \verbatim   +   >          STOREV is CHARACTER*1   +   >          Indicates how the vectors which define the elementary   +   >          reflectors are stored:   +   >          = 'C': Columnwise   +   >          = 'R': Rowwise   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The order of the matrix T (= the number of elementary   +   >          reflectors whose product defines the block reflector).   +   > \endverbatim   +   >   +   > \param[in] V   +   > \verbatim   +   >          V is 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.   +   > \endverbatim   +   >   +   > \param[in] LDV   +   > \verbatim   +   >          LDV is 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.   +   > \endverbatim   +   >   +   > \param[in] T   +   > \verbatim   +   >          T is DOUBLE PRECISION array, dimension (LDT,K)   +   >          The triangular k by k matrix T in the representation of the   +   >          block reflector.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the array T. LDT >= K.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (LDWORK,K)   +   > \endverbatim   +   >   +   > \param[in] LDWORK   +   > \verbatim   +   >          LDWORK is INTEGER   +   >          The leading dimension of the array WORK.   +   >          If SIDE = 'L', LDWORK >= max(1,N);   +   >          if SIDE = 'R', LDWORK >= max(1,M).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date June 2013   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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 )   +   > \endverbatim   +   >   +    =====================================================================   +   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 *);+    extern /* Subroutine */ int igraphdcopy_(integer *, doublereal *, integer *, +	    doublereal *, integer *), igraphdtrmm_(char *, char *, char *, char *, +	    integer *, integer *, doublereal *, doublereal *, integer *, +	    doublereal *, integer *);+    char transt[1];+++/*  -- LAPACK auxiliary routine (version 3.5.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       June 2013   +++    =====================================================================   +++       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 )   ++                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_(n, &c__[j + c_dim1], ldc, &work[j * work_dim1 + 1],+			     &c__1);+/* L10: */+		}++/*              W := W * V1 */++		igraphdtrmm_("Right", "Lower", "No transpose", "Unit", n, k, &c_b14,+			 &v[v_offset], ldv, &work[work_offset], ldwork);+		if (*m > *k) {++/*                 W := W + C2**T * V2 */++		    i__1 = *m - *k;+		    igraphdgemm_("Transpose", "No transpose", n, 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", n, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - V * W**T */++		if (*m > *k) {++/*                 C2 := C2 - V2 * W**T */++		    i__1 = *m - *k;+		    igraphdgemm_("No transpose", "Transpose", &i__1, n, 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", n, 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 = *n;+		    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 )   ++                W := C * V  =  (C1*V1 + C2*V2)  (stored in WORK)   ++                W := C1 */++		i__1 = *k;+		for (j = 1; j <= i__1; ++j) {+		    igraphdcopy_(m, &c__[j * c_dim1 + 1], &c__1, &work[j * +			    work_dim1 + 1], &c__1);+/* L40: */+		}++/*              W := W * V1 */++		igraphdtrmm_("Right", "Lower", "No transpose", "Unit", m, k, &c_b14,+			 &v[v_offset], ldv, &work[work_offset], ldwork);+		if (*n > *k) {++/*                 W := W + C2 * V2 */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "No transpose", m, 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", m, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - W * V**T */++		if (*n > *k) {++/*                 C2 := C2 - W * V2**T */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "Transpose", m, &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", m, 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 = *m;+		    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 )   ++                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_(n, &c__[*m - *k + j + c_dim1], ldc, &work[j * +			    work_dim1 + 1], &c__1);+/* L70: */+		}++/*              W := W * V2 */++		igraphdtrmm_("Right", "Upper", "No transpose", "Unit", n, k, &c_b14,+			 &v[*m - *k + 1 + v_dim1], ldv, &work[work_offset], +			ldwork);+		if (*m > *k) {++/*                 W := W + C1**T * V1 */++		    i__1 = *m - *k;+		    igraphdgemm_("Transpose", "No transpose", n, 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", n, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - V * W**T */++		if (*m > *k) {++/*                 C1 := C1 - V1 * W**T */++		    i__1 = *m - *k;+		    igraphdgemm_("No transpose", "Transpose", &i__1, n, 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", n, k, &c_b14, &+			v[*m - *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 = *n;+		    for (i__ = 1; i__ <= i__2; ++i__) {+			c__[*m - *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 )   ++                W := C * V  =  (C1*V1 + C2*V2)  (stored in WORK)   ++                W := C2 */++		i__1 = *k;+		for (j = 1; j <= i__1; ++j) {+		    igraphdcopy_(m, &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", m, k, &c_b14,+			 &v[*n - *k + 1 + v_dim1], ldv, &work[work_offset], +			ldwork);+		if (*n > *k) {++/*                 W := W + C1 * V1 */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "No transpose", m, 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", m, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - W * V**T */++		if (*n > *k) {++/*                 C1 := C1 - W * V1**T */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "Transpose", m, &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", m, k, &c_b14, &+			v[*n - *k + 1 + v_dim1], ldv, &work[work_offset], +			ldwork);++/*              C2 := C2 - W */++		i__1 = *k;+		for (j = 1; j <= i__1; ++j) {+		    i__2 = *m;+		    for (i__ = 1; i__ <= i__2; ++i__) {+			c__[i__ + (*n - *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 )   ++                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_(n, &c__[j + c_dim1], ldc, &work[j * work_dim1 + 1],+			     &c__1);+/* L130: */+		}++/*              W := W * V1**T */++		igraphdtrmm_("Right", "Upper", "Transpose", "Unit", n, k, &c_b14, &+			v[v_offset], ldv, &work[work_offset], ldwork);+		if (*m > *k) {++/*                 W := W + C2**T * V2**T */++		    i__1 = *m - *k;+		    igraphdgemm_("Transpose", "Transpose", n, 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", n, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - V**T * W**T */++		if (*m > *k) {++/*                 C2 := C2 - V2**T * W**T */++		    i__1 = *m - *k;+		    igraphdgemm_("Transpose", "Transpose", &i__1, n, 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", n, 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 = *n;+		    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 )   ++                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_(m, &c__[j * c_dim1 + 1], &c__1, &work[j * +			    work_dim1 + 1], &c__1);+/* L160: */+		}++/*              W := W * V1**T */++		igraphdtrmm_("Right", "Upper", "Transpose", "Unit", m, k, &c_b14, &+			v[v_offset], ldv, &work[work_offset], ldwork);+		if (*n > *k) {++/*                 W := W + C2 * V2**T */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "Transpose", m, 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", m, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - W * V */++		if (*n > *k) {++/*                 C2 := C2 - W * V2 */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "No transpose", m, &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", m, 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 = *m;+		    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 )   ++                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_(n, &c__[*m - *k + j + c_dim1], ldc, &work[j * +			    work_dim1 + 1], &c__1);+/* L190: */+		}++/*              W := W * V2**T */++		igraphdtrmm_("Right", "Lower", "Transpose", "Unit", n, k, &c_b14, &+			v[(*m - *k + 1) * v_dim1 + 1], ldv, &work[work_offset]+			, ldwork);+		if (*m > *k) {++/*                 W := W + C1**T * V1**T */++		    i__1 = *m - *k;+		    igraphdgemm_("Transpose", "Transpose", n, 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", n, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - V**T * W**T */++		if (*m > *k) {++/*                 C1 := C1 - V1**T * W**T */++		    i__1 = *m - *k;+		    igraphdgemm_("Transpose", "Transpose", &i__1, n, 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", n, k, &c_b14,+			 &v[(*m - *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 = *n;+		    for (i__ = 1; i__ <= i__2; ++i__) {+			c__[*m - *k + j + i__ * c_dim1] -= work[i__ + j * +				work_dim1];+/* L200: */+		    }+/* L210: */+		}++	    } else if (igraphlsame_(side, "R")) {++/*              Form  C * H  or  C * H'  where  C = ( C1  C2 )   ++                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_(m, &c__[(*n - *k + j) * c_dim1 + 1], &c__1, &work[+			    j * work_dim1 + 1], &c__1);+/* L220: */+		}++/*              W := W * V2**T */++		igraphdtrmm_("Right", "Lower", "Transpose", "Unit", m, k, &c_b14, &+			v[(*n - *k + 1) * v_dim1 + 1], ldv, &work[work_offset]+			, ldwork);+		if (*n > *k) {++/*                 W := W + C1 * V1**T */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "Transpose", m, 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", m, k, &c_b14, &t[+			t_offset], ldt, &work[work_offset], ldwork);++/*              C := C - W * V */++		if (*n > *k) {++/*                 C1 := C1 - W * V1 */++		    i__1 = *n - *k;+		    igraphdgemm_("No transpose", "No transpose", m, &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", m, k, &c_b14,+			 &v[(*n - *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 = *m;+		    for (i__ = 1; i__ <= i__2; ++i__) {+			c__[i__ + (*n - *k + j) * c_dim1] -= work[i__ + j * +				work_dim1];+/* L230: */+		    }+/* L240: */+		}++	    }++	}+    }++    return 0;++/*     End of DLARFB */++} /* igraphdlarfb_ */+
+ igraph/src/dlarfg.c view
@@ -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"++/* > \brief \b DLARFG generates an elementary reflector (Householder matrix).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARFG + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarfg.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarfg.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarfg.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARFG( N, ALPHA, X, INCX, TAU )   ++         INTEGER            INCX, N   +         DOUBLE PRECISION   ALPHA, TAU   +         DOUBLE PRECISION   X( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the elementary reflector.   +   > \endverbatim   +   >   +   > \param[in,out] ALPHA   +   > \verbatim   +   >          ALPHA is DOUBLE PRECISION   +   >          On entry, the value alpha.   +   >          On exit, it is overwritten with the value beta.   +   > \endverbatim   +   >   +   > \param[in,out] X   +   > \verbatim   +   >          X is DOUBLE PRECISION array, dimension   +   >                         (1+(N-2)*abs(INCX))   +   >          On entry, the vector x.   +   >          On exit, it is overwritten with the vector v.   +   > \endverbatim   +   >   +   > \param[in] INCX   +   > \verbatim   +   >          INCX is INTEGER   +   >          The increment between elements of X. INCX > 0.   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION   +   >          The value tau.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarft.c view
@@ -0,0 +1,438 @@+/* dlarft.f -- 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.;++/* > \brief \b DLARFT forms the triangular factor T of a block reflector H = I - vtvH */++/*  =========== DOCUMENTATION =========== */++/* Online html documentation available at */+/*            http://www.netlib.org/lapack/explore-html/ */++/* > \htmlonly */+/* > Download DLARFT + dependencies */+/* > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarft.+f"> */+/* > [TGZ]</a> */+/* > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarft.+f"> */+/* > [ZIP]</a> */+/* > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarft.+f"> */+/* > [TXT]</a> */+/* > \endhtmlonly */++/*  Definition: */+/*  =========== */++/*       SUBROUTINE DLARFT( DIRECT, STOREV, N, K, V, LDV, TAU, T, LDT ) */++/*       .. Scalar Arguments .. */+/*       CHARACTER          DIRECT, STOREV */+/*       INTEGER            K, LDT, LDV, N */+/*       .. */+/*       .. Array Arguments .. */+/*       DOUBLE PRECISION   T( LDT, * ), TAU( * ), V( LDV, * ) */+/*       .. */+++/* > \par Purpose: */+/*  ============= */+/* > */+/* > \verbatim */+/* > */+/* > 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 */+/* > \endverbatim */++/*  Arguments: */+/*  ========== */++/* > \param[in] DIRECT */+/* > \verbatim */+/* >          DIRECT is 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) */+/* > \endverbatim */+/* > */+/* > \param[in] STOREV */+/* > \verbatim */+/* >          STOREV is CHARACTER*1 */+/* >          Specifies how the vectors which define the elementary */+/* >          reflectors are stored (see also Further Details): */+/* >          = 'C': columnwise */+/* >          = 'R': rowwise */+/* > \endverbatim */+/* > */+/* > \param[in] N */+/* > \verbatim */+/* >          N is INTEGER */+/* >          The order of the block reflector H. N >= 0. */+/* > \endverbatim */+/* > */+/* > \param[in] K */+/* > \verbatim */+/* >          K is INTEGER */+/* >          The order of the triangular factor T (= the number of */+/* >          elementary reflectors). K >= 1. */+/* > \endverbatim */+/* > */+/* > \param[in] V */+/* > \verbatim */+/* >          V is DOUBLE PRECISION array, dimension */+/* >                               (LDV,K) if STOREV = 'C' */+/* >                               (LDV,N) if STOREV = 'R' */+/* >          The matrix V. See further details. */+/* > \endverbatim */+/* > */+/* > \param[in] LDV */+/* > \verbatim */+/* >          LDV is INTEGER */+/* >          The leading dimension of the array V. */+/* >          If STOREV = 'C', LDV >= max(1,N); if STOREV = 'R', LDV >= K. */+/* > \endverbatim */+/* > */+/* > \param[in] TAU */+/* > \verbatim */+/* >          TAU is DOUBLE PRECISION array, dimension (K) */+/* >          TAU(i) must contain the scalar factor of the elementary */+/* >          reflector H(i). */+/* > \endverbatim */+/* > */+/* > \param[out] T */+/* > \verbatim */+/* >          T is 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. */+/* > \endverbatim */+/* > */+/* > \param[in] LDT */+/* > \verbatim */+/* >          LDT is INTEGER */+/* >          The leading dimension of the array T. LDT >= K. */+/* > \endverbatim */++/*  Authors: */+/*  ======== */++/* > \author Univ. of Tennessee */+/* > \author Univ. of California Berkeley */+/* > \author Univ. of Colorado Denver */+/* > \author NAG Ltd. */++/* > \date September 2012 */++/* > \ingroup doubleOTHERauxiliary */++/* > \par Further Details: */+/*  ===================== */+/* > */+/* > \verbatim */+/* > */+/* >  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. */+/* > */+/* >  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 ) */+/* > \endverbatim */+/* > */+/*  ===================================================================== */+/* 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;+    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.4.2) -- */+/*  -- LAPACK is a software package provided by Univ. of Tennessee,    -- */+/*  -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..-- */+/*     September 2012 */++/*     .. Scalar Arguments .. */+/*     .. */+/*     .. Array Arguments .. */+/*     .. */++/*  ===================================================================== */++/*     .. Parameters .. */+/*     .. */+/*     .. Local Scalars .. */+/*     .. */+/*     .. External Subroutines .. */+/*     .. */+/*     .. External Functions .. */+/*     .. */+/*     .. Executable Statements .. */++/*     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.;+		}+	    } else {++/*              general case */++		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 */+		    i__2 = i__ - 1;+		    for (j = 1; j <= i__2; ++j) {+			t[j + i__ * t_dim1] = -tau[i__] * v[i__ + j * v_dim1];+		    }+		    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__;+		    i__3 = i__ - 1;+		    d__1 = -tau[i__];+		    igraphdgemv_("Transpose", &i__2, &i__3, &d__1, &v[i__ + 1 + +			    v_dim1], ldv, &v[i__ + 1 + i__ * v_dim1], &c__1, &+			    c_b8, &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 */+		    i__2 = i__ - 1;+		    for (j = 1; j <= i__2; ++j) {+			t[j + i__ * t_dim1] = -tau[i__] * v[j + i__ * v_dim1];+		    }+		    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__;+		    d__1 = -tau[i__];+		    igraphdgemv_("No transpose", &i__2, &i__3, &d__1, &v[(i__ + 1) *+			     v_dim1 + 1], ldv, &v[i__ + (i__ + 1) * v_dim1], +			    ldv, &c_b8, &t[i__ * t_dim1 + 1], &c__1);+		}++/*              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;+		}+	    }+	}+    } 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.;+		}+	    } else {++/*              general case */++		if (i__ < *k) {+		    if (igraphlsame_(storev, "C")) {+/*                    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 */+			i__1 = *k;+			for (j = i__ + 1; j <= i__1; ++j) {+			    t[j + i__ * t_dim1] = -tau[i__] * v[*n - *k + i__ +				    + j * v_dim1];+			}+			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;+			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_b8, &t[i__ + 1 + i__ * t_dim1], &+				c__1);+		    } else {+/*                    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 */+			i__1 = *k;+			for (j = i__ + 1; j <= i__1; ++j) {+			    t[j + i__ * t_dim1] = -tau[i__] * v[j + (*n - *k +				    + i__) * v_dim1];+			}+			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;+			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_b8, &t[i__ + 1 + i__ * t_dim1], &c__1+				 );+		    }++/*                 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__];+	    }+	}+    }+    return 0;++/*     End of DLARFT */++} /* dlarft_ */+
+ igraph/src/dlarfx.c view
@@ -0,0 +1,790 @@+/*  -- 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;++/* > \brief \b DLARFX applies an elementary reflector to a general rectangular matrix, with loop unrolling whe+n the reflector has order ≤ 10.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARFX + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarfx.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarfx.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarfx.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARFX( SIDE, M, N, V, TAU, C, LDC, WORK )   ++         CHARACTER          SIDE   +         INTEGER            LDC, M, N   +         DOUBLE PRECISION   TAU   +         DOUBLE PRECISION   C( LDC, * ), V( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': form  H * C   +   >          = 'R': form  C * H   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C.   +   > \endverbatim   +   >   +   > \param[in] V   +   > \verbatim   +   >          V is DOUBLE PRECISION array, dimension (M) if SIDE = 'L'   +   >                                     or (N) if SIDE = 'R'   +   >          The vector v in the representation of H.   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION   +   >          The value tau in the representation of H.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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'.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDA >= (1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension   +   >                      (N) if SIDE = 'L'   +   >                      or (M) if SIDE = 'R'   +   >          WORK is not referenced if H has order < 11.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarnv.c view
@@ -0,0 +1,193 @@+/*  -- 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"++/* > \brief \b DLARNV returns a vector of random numbers from a uniform or normal distribution.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARNV + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarnv.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarnv.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarnv.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARNV( IDIST, ISEED, N, X )   ++         INTEGER            IDIST, N   +         INTEGER            ISEED( 4 )   +         DOUBLE PRECISION   X( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLARNV returns a vector of n random real numbers from a uniform or   +   > normal distribution.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] IDIST   +   > \verbatim   +   >          IDIST is INTEGER   +   >          Specifies the distribution of the random numbers:   +   >          = 1:  uniform (0,1)   +   >          = 2:  uniform (-1,1)   +   >          = 3:  normal (0,1)   +   > \endverbatim   +   >   +   > \param[in,out] ISEED   +   > \verbatim   +   >          ISEED is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of random numbers to be generated.   +   > \endverbatim   +   >   +   > \param[out] X   +   > \verbatim   +   >          X is DOUBLE PRECISION array, dimension (N)   +   >          The generated random numbers.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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.   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarra.c view
@@ -0,0 +1,219 @@+/*  -- 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"++/* > \brief \b DLARRA computes the splitting points with the specified threshold.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRA + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarra.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarra.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarra.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRA( N, D, E, E2, SPLTOL, TNRM,   +                             NSPLIT, ISPLIT, INFO )   ++         INTEGER            INFO, N, NSPLIT   +         DOUBLE PRECISION    SPLTOL, TNRM   +         INTEGER            ISPLIT( * )   +         DOUBLE PRECISION   D( * ), E( * ), E2( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > Compute the splitting points with threshold SPLTOL.   +   > DLARRA sets any "small" off-diagonal elements to zero.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix. N > 0.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          On entry, the N diagonal elements of the tridiagonal   +   >          matrix T.   +   > \endverbatim   +   >   +   > \param[in,out] E   +   > \verbatim   +   >          E is 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.   +   > \endverbatim   +   >   +   > \param[in,out] E2   +   > \verbatim   +   >          E2 is 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   +   > \endverbatim   +   >   +   > \param[in] SPLTOL   +   > \verbatim   +   >          SPLTOL is 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   +   > \endverbatim   +   >   +   > \param[in] TNRM   +   > \verbatim   +   >          TNRM is DOUBLE PRECISION   +   >          The norm of the matrix.   +   > \endverbatim   +   >   +   > \param[out] NSPLIT   +   > \verbatim   +   >          NSPLIT is INTEGER   +   >          The number of blocks T splits into. 1 <= NSPLIT <= N.   +   > \endverbatim   +   >   +   > \param[out] ISPLIT   +   > \verbatim   +   >          ISPLIT is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarrb.c view
@@ -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"++/* > \brief \b DLARRB provides limited bisection to locate eigenvalues for more accuracy.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRB + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrb.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrb.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrb.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRB( N, D, LLD, IFIRST, ILAST, RTOL1,   +                            RTOL2, OFFSET, W, WGAP, WERR, WORK, IWORK,   +                            PIVMIN, SPDIAM, TWIST, INFO )   ++         INTEGER            IFIRST, ILAST, INFO, N, OFFSET, TWIST   +         DOUBLE PRECISION   PIVMIN, RTOL1, RTOL2, SPDIAM   +         INTEGER            IWORK( * )   +         DOUBLE PRECISION   D( * ), LLD( * ), W( * ),   +        $                   WERR( * ), WGAP( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The N diagonal elements of the diagonal matrix D.   +   > \endverbatim   +   >   +   > \param[in] LLD   +   > \verbatim   +   >          LLD is DOUBLE PRECISION array, dimension (N-1)   +   >          The (N-1) elements L(i)*L(i)*D(i).   +   > \endverbatim   +   >   +   > \param[in] IFIRST   +   > \verbatim   +   >          IFIRST is INTEGER   +   >          The index of the first eigenvalue to be computed.   +   > \endverbatim   +   >   +   > \param[in] ILAST   +   > \verbatim   +   >          ILAST is INTEGER   +   >          The index of the last eigenvalue to be computed.   +   > \endverbatim   +   >   +   > \param[in] RTOL1   +   > \verbatim   +   >          RTOL1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] RTOL2   +   > \verbatim   +   >          RTOL2 is 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.   +   > \endverbatim   +   >   +   > \param[in] OFFSET   +   > \verbatim   +   >          OFFSET is 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.   +   > \endverbatim   +   >   +   > \param[in,out] W   +   > \verbatim   +   >          W is 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.   +   > \endverbatim   +   >   +   > \param[in,out] WGAP   +   > \verbatim   +   >          WGAP is 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.   +   > \endverbatim   +   >   +   > \param[in,out] WERR   +   > \verbatim   +   >          WERR is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (2*N)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (2*N)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot in the Sturm sequence.   +   > \endverbatim   +   >   +   > \param[in] SPDIAM   +   > \verbatim   +   >          SPDIAM is DOUBLE PRECISION   +   >          The spectral diameter of the matrix.   +   > \endverbatim   +   >   +   > \param[in] TWIST   +   > \verbatim   +   >          TWIST is 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)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          Error flag.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   ++++       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_ */+
+ igraph/src/dlarrc.c view
@@ -0,0 +1,255 @@+/*  -- 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"++/* > \brief \b DLARRC computes the number of eigenvalues of the symmetric tridiagonal matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRC + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrc.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrc.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrc.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRC( JOBT, N, VL, VU, D, E, PIVMIN,   +                                     EIGCNT, LCNT, RCNT, INFO )   ++         CHARACTER          JOBT   +         INTEGER            EIGCNT, INFO, LCNT, N, RCNT   +         DOUBLE PRECISION   PIVMIN, VL, VU   +         DOUBLE PRECISION   D( * ), E( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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'.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOBT   +   > \verbatim   +   >          JOBT is CHARACTER*1   +   >          = 'T':  Compute Sturm count for matrix T.   +   >          = 'L':  Compute Sturm count for matrix L D L^T.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix. N > 0.   +   > \endverbatim   +   >   +   > \param[in] VL   +   > \verbatim   +   >          VL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] VU   +   > \verbatim   +   >          VU is DOUBLE PRECISION   +   >          The lower and upper bounds for the eigenvalues.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is 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.   +   > \endverbatim   +   >   +   > \param[in] E   +   > \verbatim   +   >          E is 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.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot in the Sturm sequence for T.   +   > \endverbatim   +   >   +   > \param[out] EIGCNT   +   > \verbatim   +   >          EIGCNT is INTEGER   +   >          The number of eigenvalues of the symmetric tridiagonal matrix T   +   >          that are in the interval (VL,VU]   +   > \endverbatim   +   >   +   > \param[out] LCNT   +   > \verbatim   +   >          LCNT is INTEGER   +   > \endverbatim   +   >   +   > \param[out] RCNT   +   > \verbatim   +   >          RCNT is INTEGER   +   >          The left and right negcounts of the interval.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarrd.c view
@@ -0,0 +1,912 @@+/*  -- 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;++/* > \brief \b DLARRD computes the eigenvalues of a symmetric tridiagonal matrix to suitable accuracy.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRD + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrd.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrd.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrd.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRD( RANGE, ORDER, N, VL, VU, IL, IU, GERS,   +                             RELTOL, D, E, E2, PIVMIN, NSPLIT, ISPLIT,   +                             M, W, WERR, WL, WU, IBLOCK, INDEXW,   +                             WORK, IWORK, INFO )   ++         CHARACTER          ORDER, RANGE   +         INTEGER            IL, INFO, IU, M, N, NSPLIT   +         DOUBLE PRECISION    PIVMIN, RELTOL, VL, VU, WL, WU   +         INTEGER            IBLOCK( * ), INDEXW( * ),   +        $                   ISPLIT( * ), IWORK( * )   +         DOUBLE PRECISION   D( * ), E( * ), E2( * ),   +        $                   GERS( * ), W( * ), WERR( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] RANGE   +   > \verbatim   +   >          RANGE is 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.   +   > \endverbatim   +   >   +   > \param[in] ORDER   +   > \verbatim   +   >          ORDER is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the tridiagonal matrix T.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] VL   +   > \verbatim   +   >          VL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] VU   +   > \verbatim   +   >          VU is 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'.   +   > \endverbatim   +   >   +   > \param[in] IL   +   > \verbatim   +   >          IL is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IU   +   > \verbatim   +   >          IU is 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'.   +   > \endverbatim   +   >   +   > \param[in] GERS   +   > \verbatim   +   >          GERS is DOUBLE PRECISION array, dimension (2*N)   +   >          The N Gerschgorin intervals (the i-th Gerschgorin interval   +   >          is (GERS(2*i-1), GERS(2*i)).   +   > \endverbatim   +   >   +   > \param[in] RELTOL   +   > \verbatim   +   >          RELTOL is 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.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The n diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] E   +   > \verbatim   +   >          E is DOUBLE PRECISION array, dimension (N-1)   +   >          The (n-1) off-diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] E2   +   > \verbatim   +   >          E2 is DOUBLE PRECISION array, dimension (N-1)   +   >          The (n-1) squared off-diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot allowed in the Sturm sequence for T.   +   > \endverbatim   +   >   +   > \param[in] NSPLIT   +   > \verbatim   +   >          NSPLIT is INTEGER   +   >          The number of diagonal blocks in the matrix T.   +   >          1 <= NSPLIT <= N.   +   > \endverbatim   +   >   +   > \param[in] ISPLIT   +   > \verbatim   +   >          ISPLIT is 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.)   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is INTEGER   +   >          The actual number of eigenvalues found. 0 <= M <= N.   +   >          (See also the description of INFO=2,3.)   +   > \endverbatim   +   >   +   > \param[out] W   +   > \verbatim   +   >          W is 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   +   > \endverbatim   +   >   +   > \param[out] WERR   +   > \verbatim   +   >          WERR is DOUBLE PRECISION array, dimension (N)   +   >          The error bound on the corresponding eigenvalue approximation   +   >          in W.   +   > \endverbatim   +   >   +   > \param[out] WL   +   > \verbatim   +   >          WL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] WU   +   > \verbatim   +   >          WU is 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.   +   > \endverbatim   +   >   +   > \param[out] IBLOCK   +   > \verbatim   +   >          IBLOCK is 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.)   +   > \endverbatim   +   >   +   > \param[out] INDEXW   +   > \verbatim   +   >          INDEXW is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (4*N)   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (3*N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++   > \par Internal Parameters:   +    =========================   +   >   +   > \verbatim   +   >  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.   +   > \endverbatim   +   >   +   > \par Contributors:   +    ==================   +   >   +   >     W. Kahan, University of California, Berkeley, USA \n   +   >     Beresford Parlett, University of California, Berkeley, USA \n   +   >     Jim Demmel, University of California, Berkeley, USA \n   +   >     Inderjit Dhillon, University of Texas, Austin, USA \n   +   >     Osni Marques, LBNL/NERSC, USA \n   +   >     Christof Voemel, University of California, Berkeley, USA \n   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarre.c view
@@ -0,0 +1,986 @@+/*  -- 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;++/* > \brief \b DLARRE given the tridiagonal matrix T, sets small off-diagonal elements to zero and for each un+reduced block Ti, finds base representations and eigenvalues.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRE + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarre.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarre.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarre.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRE( RANGE, N, VL, VU, IL, IU, D, E, E2,   +                             RTOL1, RTOL2, SPLTOL, NSPLIT, ISPLIT, M,   +                             W, WERR, WGAP, IBLOCK, INDEXW, GERS, PIVMIN,   +                             WORK, IWORK, INFO )   ++         CHARACTER          RANGE   +         INTEGER            IL, INFO, IU, M, N, NSPLIT   +         DOUBLE PRECISION  PIVMIN, RTOL1, RTOL2, SPLTOL, VL, VU   +         INTEGER            IBLOCK( * ), ISPLIT( * ), IWORK( * ),   +        $                   INDEXW( * )   +         DOUBLE PRECISION   D( * ), E( * ), E2( * ), GERS( * ),   +        $                   W( * ),WERR( * ), WGAP( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] RANGE   +   > \verbatim   +   >          RANGE is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix. N > 0.   +   > \endverbatim   +   >   +   > \param[in,out] VL   +   > \verbatim   +   >          VL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] VU   +   > \verbatim   +   >          VU is 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.   +   > \endverbatim   +   >   +   > \param[in] IL   +   > \verbatim   +   >          IL is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IU   +   > \verbatim   +   >          IU is INTEGER   +   >          If RANGE='I', the indices (in ascending order) of the   +   >          smallest and largest eigenvalues to be returned.   +   >          1 <= IL <= IU <= N.   +   > \endverbatim   +   >   +   > \param[in,out] D   +   > \verbatim   +   >          D is 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.   +   > \endverbatim   +   >   +   > \param[in,out] E   +   > \verbatim   +   >          E is 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.   +   > \endverbatim   +   >   +   > \param[in,out] E2   +   > \verbatim   +   >          E2 is 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   +   > \endverbatim   +   >   +   > \param[in] RTOL1   +   > \verbatim   +   >          RTOL1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] RTOL2   +   > \verbatim   +   >          RTOL2 is DOUBLE PRECISION   +   >           Parameters for bisection.   +   >           An interval [LEFT,RIGHT] has converged if   +   >           RIGHT-LEFT.LT.MAX( RTOL1*GAP, RTOL2*MAX(|LEFT|,|RIGHT|) )   +   > \endverbatim   +   >   +   > \param[in] SPLTOL   +   > \verbatim   +   >          SPLTOL is DOUBLE PRECISION   +   >          The threshold for splitting.   +   > \endverbatim   +   >   +   > \param[out] NSPLIT   +   > \verbatim   +   >          NSPLIT is INTEGER   +   >          The number of blocks T splits into. 1 <= NSPLIT <= N.   +   > \endverbatim   +   >   +   > \param[out] ISPLIT   +   > \verbatim   +   >          ISPLIT is 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.   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is INTEGER   +   >          The total number of eigenvalues (of all L_i D_i L_i^T)   +   >          found.   +   > \endverbatim   +   >   +   > \param[out] W   +   > \verbatim   +   >          W is 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).   +   > \endverbatim   +   >   +   > \param[out] WERR   +   > \verbatim   +   >          WERR is DOUBLE PRECISION array, dimension (N)   +   >          The error bound on the corresponding eigenvalue in W.   +   > \endverbatim   +   >   +   > \param[out] WGAP   +   > \verbatim   +   >          WGAP is 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   +   > \endverbatim   +   >   +   > \param[out] IBLOCK   +   > \verbatim   +   >          IBLOCK is 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.   +   > \endverbatim   +   >   +   > \param[out] INDEXW   +   > \verbatim   +   >          INDEXW is 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   +   > \endverbatim   +   >   +   > \param[out] GERS   +   > \verbatim   +   >          GERS is DOUBLE PRECISION array, dimension (2*N)   +   >          The N Gerschgorin intervals (the i-th Gerschgorin interval   +   >          is (GERS(2*i-1), GERS(2*i)).   +   > \endverbatim   +   >   +   > \param[out] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot in the Sturm sequence for T.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (6*N)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (5*N)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  The base representations are required to suffer very little   +   >  element growth and consequently define all their eigenvalues to   +   >  high relative accuracy.   +   > \endverbatim   ++   > \par Contributors:   +    ==================   +   >   +   >     Beresford Parlett, University of California, Berkeley, USA \n   +   >     Jim Demmel, University of California, Berkeley, USA \n   +   >     Inderjit Dhillon, University of Texas, Austin, USA \n   +   >     Osni Marques, LBNL/NERSC, USA \n   +   >     Christof Voemel, University of California, Berkeley, USA \n   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarrf.c view
@@ -0,0 +1,523 @@+/*  -- 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;++/* > \brief \b DLARRF finds a new relatively robust representation such that at least one of the eigenvalues i+s relatively isolated.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRF + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrf.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrf.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrf.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRF( N, D, L, LD, CLSTRT, CLEND,   +                            W, WGAP, WERR,   +                            SPDIAM, CLGAPL, CLGAPR, PIVMIN, SIGMA,   +                            DPLUS, LPLUS, WORK, INFO )   ++         INTEGER            CLSTRT, CLEND, INFO, N   +         DOUBLE PRECISION   CLGAPL, CLGAPR, PIVMIN, SIGMA, SPDIAM   +         DOUBLE PRECISION   D( * ), DPLUS( * ), L( * ), LD( * ),   +        $          LPLUS( * ), W( * ), WGAP( * ), WERR( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix (subblock, if the matrix splitted).   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The N diagonal elements of the diagonal matrix D.   +   > \endverbatim   +   >   +   > \param[in] L   +   > \verbatim   +   >          L is DOUBLE PRECISION array, dimension (N-1)   +   >          The (N-1) subdiagonal elements of the unit bidiagonal   +   >          matrix L.   +   > \endverbatim   +   >   +   > \param[in] LD   +   > \verbatim   +   >          LD is DOUBLE PRECISION array, dimension (N-1)   +   >          The (N-1) elements L(i)*D(i).   +   > \endverbatim   +   >   +   > \param[in] CLSTRT   +   > \verbatim   +   >          CLSTRT is INTEGER   +   >          The index of the first eigenvalue in the cluster.   +   > \endverbatim   +   >   +   > \param[in] CLEND   +   > \verbatim   +   >          CLEND is INTEGER   +   >          The index of the last eigenvalue in the cluster.   +   > \endverbatim   +   >   +   > \param[in] W   +   > \verbatim   +   >          W is 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.   +   > \endverbatim   +   >   +   > \param[in,out] WGAP   +   > \verbatim   +   >          WGAP is DOUBLE PRECISION array, dimension   +   >          dimension is >=  (CLEND-CLSTRT+1)   +   >          The separation from the right neighbor eigenvalue in W.   +   > \endverbatim   +   >   +   > \param[in] WERR   +   > \verbatim   +   >          WERR is DOUBLE PRECISION array, dimension   +   >          dimension is  >=  (CLEND-CLSTRT+1)   +   >          WERR contain the semiwidth of the uncertainty   +   >          interval of the corresponding eigenvalue APPROXIMATION in W   +   > \endverbatim   +   >   +   > \param[in] SPDIAM   +   > \verbatim   +   >          SPDIAM is DOUBLE PRECISION   +   >          estimate of the spectral diameter obtained from the   +   >          Gerschgorin intervals   +   > \endverbatim   +   >   +   > \param[in] CLGAPL   +   > \verbatim   +   >          CLGAPL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] CLGAPR   +   > \verbatim   +   >          CLGAPR is 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.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot allowed in the Sturm sequence.   +   > \endverbatim   +   >   +   > \param[out] SIGMA   +   > \verbatim   +   >          SIGMA is DOUBLE PRECISION   +   >          The shift used to form L(+) D(+) L(+)^T.   +   > \endverbatim   +   >   +   > \param[out] DPLUS   +   > \verbatim   +   >          DPLUS is DOUBLE PRECISION array, dimension (N)   +   >          The N diagonal elements of the diagonal matrix D(+).   +   > \endverbatim   +   >   +   > \param[out] LPLUS   +   > \verbatim   +   >          LPLUS is DOUBLE PRECISION array, dimension (N-1)   +   >          The first (N-1) elements of LPLUS contain the subdiagonal   +   >          elements of the unit bidiagonal matrix L(+).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (2*N)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          Signals processing OK (=0) or failure (=1)   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarrj.c view
@@ -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"++/* > \brief \b DLARRJ performs refinement of the initial estimates of the eigenvalues of the matrix T.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRJ + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrj.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrj.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrj.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRJ( N, D, E2, IFIRST, ILAST,   +                            RTOL, OFFSET, W, WERR, WORK, IWORK,   +                            PIVMIN, SPDIAM, INFO )   ++         INTEGER            IFIRST, ILAST, INFO, N, OFFSET   +         DOUBLE PRECISION   PIVMIN, RTOL, SPDIAM   +         INTEGER            IWORK( * )   +         DOUBLE PRECISION   D( * ), E2( * ), W( * ),   +        $                   WERR( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The N diagonal elements of T.   +   > \endverbatim   +   >   +   > \param[in] E2   +   > \verbatim   +   >          E2 is DOUBLE PRECISION array, dimension (N-1)   +   >          The Squares of the (N-1) subdiagonal elements of T.   +   > \endverbatim   +   >   +   > \param[in] IFIRST   +   > \verbatim   +   >          IFIRST is INTEGER   +   >          The index of the first eigenvalue to be computed.   +   > \endverbatim   +   >   +   > \param[in] ILAST   +   > \verbatim   +   >          ILAST is INTEGER   +   >          The index of the last eigenvalue to be computed.   +   > \endverbatim   +   >   +   > \param[in] RTOL   +   > \verbatim   +   >          RTOL is DOUBLE PRECISION   +   >          Tolerance for the convergence of the bisection intervals.   +   >          An interval [LEFT,RIGHT] has converged if   +   >          RIGHT-LEFT.LT.RTOL*MAX(|LEFT|,|RIGHT|).   +   > \endverbatim   +   >   +   > \param[in] OFFSET   +   > \verbatim   +   >          OFFSET is INTEGER   +   >          Offset for the arrays W and WERR, i.e., the IFIRST-OFFSET   +   >          through ILAST-OFFSET elements of these arrays are to be used.   +   > \endverbatim   +   >   +   > \param[in,out] W   +   > \verbatim   +   >          W is 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.   +   > \endverbatim   +   >   +   > \param[in,out] WERR   +   > \verbatim   +   >          WERR is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (2*N)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (2*N)   +   >          Workspace.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot in the Sturm sequence for T.   +   > \endverbatim   +   >   +   > \param[in] SPDIAM   +   > \verbatim   +   >          SPDIAM is DOUBLE PRECISION   +   >          The spectral diameter of T.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          Error flag.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   ++++       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_ */+
+ igraph/src/dlarrk.c view
@@ -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"++/* > \brief \b DLARRK computes one eigenvalue of a symmetric tridiagonal matrix T to suitable accuracy.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRK + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrk.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrk.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrk.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRK( N, IW, GL, GU,   +                             D, E2, PIVMIN, RELTOL, W, WERR, INFO)   ++         INTEGER   INFO, IW, N   +         DOUBLE PRECISION    PIVMIN, RELTOL, GL, GU, W, WERR   +         DOUBLE PRECISION   D( * ), E2( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the tridiagonal matrix T.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] IW   +   > \verbatim   +   >          IW is INTEGER   +   >          The index of the eigenvalues to be returned.   +   > \endverbatim   +   >   +   > \param[in] GL   +   > \verbatim   +   >          GL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] GU   +   > \verbatim   +   >          GU is DOUBLE PRECISION   +   >          An upper and a lower bound on the eigenvalue.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The n diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] E2   +   > \verbatim   +   >          E2 is DOUBLE PRECISION array, dimension (N-1)   +   >          The (n-1) squared off-diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot allowed in the Sturm sequence for T.   +   > \endverbatim   +   >   +   > \param[in] RELTOL   +   > \verbatim   +   >          RELTOL is 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.   +   > \endverbatim   +   >   +   > \param[out] W   +   > \verbatim   +   >          W is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[out] WERR   +   > \verbatim   +   >          WERR is DOUBLE PRECISION   +   >          The error bound on the corresponding eigenvalue approximation   +   >          in W.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:       Eigenvalue converged   +   >          = -1:      Eigenvalue did NOT converge   +   > \endverbatim   ++   > \par Internal Parameters:   +    =========================   +   >   +   > \verbatim   +   >  FUDGE   DOUBLE PRECISION, default = 2   +   >          A "fudge factor" to widen the Gershgorin intervals.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlarrr.c view
@@ -0,0 +1,222 @@+/*  -- 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"++/* > \brief \b DLARRR performs tests to decide whether the symmetric tridiagonal matrix T warrants expensive c+omputations which guarantee high relative accuracy in the eigenvalues.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRR( N, D, E, INFO )   ++         INTEGER            N, INFO   +         DOUBLE PRECISION   D( * ), E( * )   ++++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > Perform tests to decide whether the symmetric tridiagonal matrix T   +   > warrants expensive computations which guarantee high relative accuracy   +   > in the eigenvalues.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix. N > 0.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The N diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in,out] E   +   > \verbatim   +   >          E is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          INFO = 0(default) : the matrix warrants computations preserving   +   >                              relative accuracy.   +   >          INFO = 1          : the matrix warrants computations guaranteeing   +   >                              only absolute accuracy.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   ++++    =====================================================================   +++       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_ */+
+ igraph/src/dlarrv.c view
@@ -0,0 +1,1105 @@+/*  -- 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;++/* > \brief \b DLARRV computes the eigenvectors of the tridiagonal matrix T = L D LT given L, D and the eigenv+alues of L D LT.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARRV + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlarrv.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlarrv.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlarrv.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARRV( N, VL, VU, D, L, PIVMIN,   +                            ISPLIT, M, DOL, DOU, MINRGP,   +                            RTOL1, RTOL2, W, WERR, WGAP,   +                            IBLOCK, INDEXW, GERS, Z, LDZ, ISUPPZ,   +                            WORK, IWORK, INFO )   ++         INTEGER            DOL, DOU, INFO, LDZ, M, N   +         DOUBLE PRECISION   MINRGP, PIVMIN, RTOL1, RTOL2, VL, VU   +         INTEGER            IBLOCK( * ), INDEXW( * ), ISPLIT( * ),   +        $                   ISUPPZ( * ), IWORK( * )   +         DOUBLE PRECISION   D( * ), GERS( * ), L( * ), W( * ), WERR( * ),   +        $                   WGAP( * ), WORK( * )   +         DOUBLE PRECISION  Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] VL   +   > \verbatim   +   >          VL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] VU   +   > \verbatim   +   >          VU is 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.   +   > \endverbatim   +   >   +   > \param[in,out] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          On entry, the N diagonal elements of the diagonal matrix D.   +   >          On exit, D may be overwritten.   +   > \endverbatim   +   >   +   > \param[in,out] L   +   > \verbatim   +   >          L is 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.   +   > \endverbatim   +   >   +   > \param[in] PIVMIN   +   > \verbatim   +   >          PIVMIN is DOUBLE PRECISION   +   >          The minimum pivot allowed in the Sturm sequence.   +   > \endverbatim   +   >   +   > \param[in] ISPLIT   +   > \verbatim   +   >          ISPLIT is 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.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The total number of input eigenvalues.  0 <= M <= N.   +   > \endverbatim   +   >   +   > \param[in] DOL   +   > \verbatim   +   >          DOL is INTEGER   +   > \endverbatim   +   >   +   > \param[in] DOU   +   > \verbatim   +   >          DOU is 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.   +   > \endverbatim   +   >   +   > \param[in] MINRGP   +   > \verbatim   +   >          MINRGP is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] RTOL1   +   > \verbatim   +   >          RTOL1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] RTOL2   +   > \verbatim   +   >          RTOL2 is DOUBLE PRECISION   +   >           Parameters for bisection.   +   >           An interval [LEFT,RIGHT] has converged if   +   >           RIGHT-LEFT.LT.MAX( RTOL1*GAP, RTOL2*MAX(|LEFT|,|RIGHT|) )   +   > \endverbatim   +   >   +   > \param[in,out] W   +   > \verbatim   +   >          W is 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.   +   > \endverbatim   +   >   +   > \param[in,out] WERR   +   > \verbatim   +   >          WERR is DOUBLE PRECISION array, dimension (N)   +   >          The first M elements contain the semiwidth of the uncertainty   +   >          interval of the corresponding eigenvalue in W   +   > \endverbatim   +   >   +   > \param[in,out] WGAP   +   > \verbatim   +   >          WGAP is DOUBLE PRECISION array, dimension (N)   +   >          The separation from the right neighbor eigenvalue in W.   +   > \endverbatim   +   >   +   > \param[in] IBLOCK   +   > \verbatim   +   >          IBLOCK is 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.   +   > \endverbatim   +   >   +   > \param[in] INDEXW   +   > \verbatim   +   >          INDEXW is 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.   +   > \endverbatim   +   >   +   > \param[in] GERS   +   > \verbatim   +   >          GERS is 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.   +   > \endverbatim   +   >   +   > \param[out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >          The leading dimension of the array Z.  LDZ >= 1, and if   +   >          JOBZ = 'V', LDZ >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] ISUPPZ   +   > \verbatim   +   >          ISUPPZ is 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 ).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (12*N)   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (7*N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   ++       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_ */+
+ igraph/src/dlartg.c view
@@ -0,0 +1,235 @@+/*  -- 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"++/* > \brief \b DLARTG generates a plane rotation with real cosine and real sine.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARTG + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlartg.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlartg.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlartg.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARTG( F, G, CS, SN, R )   ++         DOUBLE PRECISION   CS, F, G, R, SN   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] F   +   > \verbatim   +   >          F is DOUBLE PRECISION   +   >          The first component of vector to be rotated.   +   > \endverbatim   +   >   +   > \param[in] G   +   > \verbatim   +   >          G is DOUBLE PRECISION   +   >          The second component of vector to be rotated.   +   > \endverbatim   +   >   +   > \param[out] CS   +   > \verbatim   +   >          CS is DOUBLE PRECISION   +   >          The cosine of the rotation.   +   > \endverbatim   +   >   +   > \param[out] SN   +   > \verbatim   +   >          SN is DOUBLE PRECISION   +   >          The sine of the rotation.   +   > \endverbatim   +   >   +   > \param[out] R   +   > \verbatim   +   >          R is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   ++       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_ */+
+ igraph/src/dlaruv.c view
@@ -0,0 +1,236 @@+/*  -- 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"++/* > \brief \b DLARUV returns a vector of n random real numbers from a uniform distribution.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLARUV + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaruv.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaruv.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaruv.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLARUV( ISEED, N, X )   ++         INTEGER            N   +         INTEGER            ISEED( 4 )   +         DOUBLE PRECISION   X( N )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in,out] ISEED   +   > \verbatim   +   >          ISEED is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of random numbers to be generated. N <= 128.   +   > \endverbatim   +   >   +   > \param[out] X   +   > \verbatim   +   >          X is DOUBLE PRECISION array, dimension (N)   +   >          The generated random numbers.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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.   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   ++       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_ */+
+ igraph/src/dlascl.c view
@@ -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"++/* > \brief \b DLASCL multiplies a general rectangular matrix by a real scalar defined as cto/cfrom.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASCL + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlascl.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlascl.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlascl.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASCL( TYPE, KL, KU, CFROM, CTO, M, N, A, LDA, INFO )   ++         CHARACTER          TYPE   +         INTEGER            INFO, KL, KU, LDA, M, N   +         DOUBLE PRECISION   CFROM, CTO   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] TYPE   +   > \verbatim   +   >          TYPE is 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.   +   > \endverbatim   +   >   +   > \param[in] KL   +   > \verbatim   +   >          KL is INTEGER   +   >          The lower bandwidth of A.  Referenced only if TYPE = 'B',   +   >          'Q' or 'Z'.   +   > \endverbatim   +   >   +   > \param[in] KU   +   > \verbatim   +   >          KU is INTEGER   +   >          The upper bandwidth of A.  Referenced only if TYPE = 'B',   +   >          'Q' or 'Z'.   +   > \endverbatim   +   >   +   > \param[in] CFROM   +   > \verbatim   +   >          CFROM is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] CTO   +   > \verbatim   +   >          CTO is 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.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,N)   +   >          The matrix to be multiplied by CTO/CFROM.  See TYPE for the   +   >          storage type.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          0  - successful exit   +   >          <0 - if INFO = -i, the i-th argument had an illegal value.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlaset.c view
@@ -0,0 +1,211 @@+/*  -- 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"++/* > \brief \b DLASET initializes the off-diagonal elements and the diagonal elements of a matrix to given val+ues.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASET + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaset.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaset.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaset.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASET( UPLO, M, N, ALPHA, BETA, A, LDA )   ++         CHARACTER          UPLO   +         INTEGER            LDA, M, N   +         DOUBLE PRECISION   ALPHA, BETA   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLASET initializes an m-by-n matrix A to BETA on the diagonal and   +   > ALPHA on the offdiagonals.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is 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.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] ALPHA   +   > \verbatim   +   >          ALPHA is DOUBLE PRECISION   +   >          The constant to which the offdiagonal elements are to be set.   +   > \endverbatim   +   >   +   > \param[in] BETA   +   > \verbatim   +   >          BETA is DOUBLE PRECISION   +   >          The constant to which the diagonal elements are to be set.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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).   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,M).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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_ */+
+ igraph/src/dlasq2.c view
@@ -0,0 +1,688 @@+/*  -- 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;++/* > \brief \b DLASQ2 computes all the eigenvalues of the symmetric positive definite tridiagonal matrix assoc+iated with the qd Array Z to high relative accuracy. Used by sbdsqr and sstegr.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASQ2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasq2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasq2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasq2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASQ2( N, Z, INFO )   ++         INTEGER            INFO, N   +         DOUBLE PRECISION   Z( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >        The number of rows and columns in the matrix. N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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 100*N   +   >                   iterations (in inner while loop).  On exit Z holds   +   >                   a qd array with the same eigenvalues as the given Z.   +   >              = 3, termination criterion of outer while loop not met   +   >                   (program created more than N unreduced blocks)   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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).   +   > \endverbatim   +   >   +    =====================================================================   +   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, i1, i4, n0, n1;+    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;+    doublereal tempe, tempq;+    integer 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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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) * 100;+	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;++/*        Maximum number of iterations exceeded, restore the shift   +          SIGMA and place the new d's and e's in a qd array.   +          This might need to be done for several blocks */++	i1 = i0;+	n1 = n0;+L145:+	tempq = z__[(i0 << 2) - 3];+	z__[(i0 << 2) - 3] += sigma;+	i__2 = n0;+	for (k = i0 + 1; k <= i__2; ++k) {+	    tempe = z__[(k << 2) - 5];+	    z__[(k << 2) - 5] *= tempq / z__[(k << 2) - 7];+	    tempq = z__[(k << 2) - 3];+	    z__[(k << 2) - 3] = z__[(k << 2) - 3] + sigma + tempe - z__[(k << +		    2) - 5];+	}++/*        Prepare to do this on the previous block if there is one */++	if (i1 > 1) {+	    n1 = i1 - 1;+	    while(i1 >= 2 && z__[(i1 << 2) - 5] >= 0.) {+		--i1;+	    }+	    sigma = -z__[(n1 << 2) - 1];+	    goto L145;+	}+	i__2 = *n;+	for (k = 1; k <= i__2; ++k) {+	    z__[(k << 1) - 1] = z__[(k << 2) - 3];++/*        Only the block 1..N0 is unfinished.  The rest of the e's   +          must be essentially zero, although sometimes other data   +          has been stored in them. */++	    if (k < n0) {+		z__[k * 2] = z__[(k << 2) - 1];+	    } else {+		z__[k * 2] = 0.;+	    }+	}+	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_ */+
+ igraph/src/dlasq3.c view
@@ -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"++/* > \brief \b DLASQ3 checks for deflation, computes a shift and calls dqds. Used by sbdsqr.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASQ3 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasq3.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasq3.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasq3.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASQ3( I0, N0, Z, PP, DMIN, SIGMA, DESIG, QMAX, NFAIL,   +                            ITER, NDIV, IEEE, TTYPE, DMIN1, DMIN2, DN, DN1,   +                            DN2, G, TAU )   ++         LOGICAL            IEEE   +         INTEGER            I0, ITER, N0, NDIV, NFAIL, PP   +         DOUBLE PRECISION   DESIG, DMIN, DMIN1, DMIN2, DN, DN1, DN2, G,   +        $                   QMAX, SIGMA, TAU   +         DOUBLE PRECISION   Z( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] I0   +   > \verbatim   +   >          I0 is INTEGER   +   >         First index.   +   > \endverbatim   +   >   +   > \param[in,out] N0   +   > \verbatim   +   >          N0 is INTEGER   +   >         Last index.   +   > \endverbatim   +   >   +   > \param[in] Z   +   > \verbatim   +   >          Z is DOUBLE PRECISION array, dimension ( 4*N )   +   >         Z holds the qd array.   +   > \endverbatim   +   >   +   > \param[in,out] PP   +   > \verbatim   +   >          PP is 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.   +   > \endverbatim   +   >   +   > \param[out] DMIN   +   > \verbatim   +   >          DMIN is DOUBLE PRECISION   +   >         Minimum value of d.   +   > \endverbatim   +   >   +   > \param[out] SIGMA   +   > \verbatim   +   >          SIGMA is DOUBLE PRECISION   +   >         Sum of shifts used in current segment.   +   > \endverbatim   +   >   +   > \param[in,out] DESIG   +   > \verbatim   +   >          DESIG is DOUBLE PRECISION   +   >         Lower order part of SIGMA   +   > \endverbatim   +   >   +   > \param[in] QMAX   +   > \verbatim   +   >          QMAX is DOUBLE PRECISION   +   >         Maximum value of q.   +   > \endverbatim   +   >   +   > \param[out] NFAIL   +   > \verbatim   +   >          NFAIL is INTEGER   +   >         Number of times shift was too big.   +   > \endverbatim   +   >   +   > \param[out] ITER   +   > \verbatim   +   >          ITER is INTEGER   +   >         Number of iterations.   +   > \endverbatim   +   >   +   > \param[out] NDIV   +   > \verbatim   +   >          NDIV is INTEGER   +   >         Number of divisions.   +   > \endverbatim   +   >   +   > \param[in] IEEE   +   > \verbatim   +   >          IEEE is LOGICAL   +   >         Flag for IEEE or non IEEE arithmetic (passed to DLASQ5).   +   > \endverbatim   +   >   +   > \param[in,out] TTYPE   +   > \verbatim   +   >          TTYPE is INTEGER   +   >         Shift type.   +   > \endverbatim   +   >   +   > \param[in,out] DMIN1   +   > \verbatim   +   >          DMIN1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] DMIN2   +   > \verbatim   +   >          DMIN2 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] DN   +   > \verbatim   +   >          DN is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] DN1   +   > \verbatim   +   >          DN1 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] DN2   +   > \verbatim   +   >          DN2 is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] G   +   > \verbatim   +   >          G is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in,out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION   +   >   +   >         These are passed as arguments in order to save their values   +   >         between calls to DLASQ3.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   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 *, doublereal *, logical *+	    , doublereal *), igraphdlasq6_(integer *, integer *, doublereal *, +	    integer *, doublereal *, doublereal *, doublereal *, doublereal *,+	     doublereal *, doublereal *);+    extern doublereal igraphdlamch_(char *);+    extern logical igraphdisnan_(doublereal *);+++/*  -- LAPACK computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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;+    }+    t = (z__[nn - 7] - z__[nn - 3] + z__[nn - 5]) * .5;+    if (z__[nn - 5] > z__[nn - 3] * tol2 && t != 0.) {+	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, sigma, dmin__, dmin1, dmin2, dn, dn1, +	    dn2, ieee, &eps);++    *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_ */+
+ igraph/src/dlasq4.c view
@@ -0,0 +1,484 @@+/*  -- 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"++/* > \brief \b DLASQ4 computes an approximation to the smallest eigenvalue using values of d from the previous+ transform. Used by sbdsqr.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASQ4 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasq4.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasq4.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasq4.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASQ4( I0, N0, Z, PP, N0IN, DMIN, DMIN1, DMIN2, DN,   +                            DN1, DN2, TAU, TTYPE, G )   ++         INTEGER            I0, N0, N0IN, PP, TTYPE   +         DOUBLE PRECISION   DMIN, DMIN1, DMIN2, DN, DN1, DN2, G, TAU   +         DOUBLE PRECISION   Z( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLASQ4 computes an approximation TAU to the smallest eigenvalue   +   > using values of d from the previous transform.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] I0   +   > \verbatim   +   >          I0 is INTEGER   +   >        First index.   +   > \endverbatim   +   >   +   > \param[in] N0   +   > \verbatim   +   >          N0 is INTEGER   +   >        Last index.   +   > \endverbatim   +   >   +   > \param[in] Z   +   > \verbatim   +   >          Z is DOUBLE PRECISION array, dimension ( 4*N )   +   >        Z holds the qd array.   +   > \endverbatim   +   >   +   > \param[in] PP   +   > \verbatim   +   >          PP is INTEGER   +   >        PP=0 for ping, PP=1 for pong.   +   > \endverbatim   +   >   +   > \param[in] N0IN   +   > \verbatim   +   >          N0IN is INTEGER   +   >        The value of N0 at start of EIGTEST.   +   > \endverbatim   +   >   +   > \param[in] DMIN   +   > \verbatim   +   >          DMIN is DOUBLE PRECISION   +   >        Minimum value of d.   +   > \endverbatim   +   >   +   > \param[in] DMIN1   +   > \verbatim   +   >          DMIN1 is DOUBLE PRECISION   +   >        Minimum value of d, excluding D( N0 ).   +   > \endverbatim   +   >   +   > \param[in] DMIN2   +   > \verbatim   +   >          DMIN2 is DOUBLE PRECISION   +   >        Minimum value of d, excluding D( N0 ) and D( N0-1 ).   +   > \endverbatim   +   >   +   > \param[in] DN   +   > \verbatim   +   >          DN is DOUBLE PRECISION   +   >        d(N)   +   > \endverbatim   +   >   +   > \param[in] DN1   +   > \verbatim   +   >          DN1 is DOUBLE PRECISION   +   >        d(N-1)   +   > \endverbatim   +   >   +   > \param[in] DN2   +   > \verbatim   +   >          DN2 is DOUBLE PRECISION   +   >        d(N-2)   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION   +   >        This is the shift.   +   > \endverbatim   +   >   +   > \param[out] TTYPE   +   > \verbatim   +   >          TTYPE is INTEGER   +   >        Shift type.   +   > \endverbatim   +   >   +   > \param[in,out] G   +   > \verbatim   +   >          G is REAL   +   >        G is passed as an argument in order to save its value between   +   >        calls to DLASQ4.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  CNST1 = 9/16   +   > \endverbatim   +   >   +    =====================================================================   +   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 = 0., a2, b1, b2;+    integer i4, nn, np;+    doublereal gam, gap1, gap2;+++/*  -- LAPACK computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlasq5.c view
@@ -0,0 +1,462 @@+/*  -- 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"++/* > \brief \b DLASQ5 computes one dqds transform in ping-pong form. Used by sbdsqr and sstegr.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASQ5 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasq5.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasq5.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasq5.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASQ5( I0, N0, Z, PP, TAU, SIGMA, DMIN, DMIN1, DMIN2, DN,   +                            DNM1, DNM2, IEEE, EPS )   ++         LOGICAL            IEEE   +         INTEGER            I0, N0, PP   +         DOUBLE PRECISION   DMIN, DMIN1, DMIN2, DN, DNM1, DNM2, TAU, SIGMA, EPS   +         DOUBLE PRECISION   Z( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLASQ5 computes one dqds transform in ping-pong form, one   +   > version for IEEE machines another for non IEEE machines.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] I0   +   > \verbatim   +   >          I0 is INTEGER   +   >        First index.   +   > \endverbatim   +   >   +   > \param[in] N0   +   > \verbatim   +   >          N0 is INTEGER   +   >        Last index.   +   > \endverbatim   +   >   +   > \param[in] Z   +   > \verbatim   +   >          Z is DOUBLE PRECISION array, dimension ( 4*N )   +   >        Z holds the qd array. EMIN is stored in Z(4*N0) to avoid   +   >        an extra argument.   +   > \endverbatim   +   >   +   > \param[in] PP   +   > \verbatim   +   >          PP is INTEGER   +   >        PP=0 for ping, PP=1 for pong.   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION   +   >        This is the shift.   +   > \endverbatim   +   >   +   > \param[in] SIGMA   +   > \verbatim   +   >          SIGMA is DOUBLE PRECISION   +   >        This is the accumulated shift up to this step.   +   > \endverbatim   +   >   +   > \param[out] DMIN   +   > \verbatim   +   >          DMIN is DOUBLE PRECISION   +   >        Minimum value of d.   +   > \endverbatim   +   >   +   > \param[out] DMIN1   +   > \verbatim   +   >          DMIN1 is DOUBLE PRECISION   +   >        Minimum value of d, excluding D( N0 ).   +   > \endverbatim   +   >   +   > \param[out] DMIN2   +   > \verbatim   +   >          DMIN2 is DOUBLE PRECISION   +   >        Minimum value of d, excluding D( N0 ) and D( N0-1 ).   +   > \endverbatim   +   >   +   > \param[out] DN   +   > \verbatim   +   >          DN is DOUBLE PRECISION   +   >        d(N0), the last value of d.   +   > \endverbatim   +   >   +   > \param[out] DNM1   +   > \verbatim   +   >          DNM1 is DOUBLE PRECISION   +   >        d(N0-1).   +   > \endverbatim   +   >   +   > \param[out] DNM2   +   > \verbatim   +   >          DNM2 is DOUBLE PRECISION   +   >        d(N0-2).   +   > \endverbatim   +   >   +   > \param[in] IEEE   +   > \verbatim   +   >          IEEE is LOGICAL   +   >        Flag for IEEE or non IEEE arithmetic.   +   > \endverbatim   ++   > \param[in] EPS   +   > \verbatim   +   >          EPS is DOUBLE PRECISION   +   >        This is the value of epsilon used.   +   > \endverbatim   +   >   +    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   Subroutine */ int igraphdlasq5_(integer *i0, integer *n0, doublereal *z__, +	integer *pp, doublereal *tau, doublereal *sigma, doublereal *dmin__, +	doublereal *dmin1, doublereal *dmin2, doublereal *dn, doublereal *+	dnm1, doublereal *dnm2, logical *ieee, doublereal *eps)+{+    /* System generated locals */+    integer i__1;+    doublereal d__1, d__2;++    /* Local variables */+    doublereal d__;+    integer j4, j4p2;+    doublereal emin, temp, dthresh;+++/*  -- LAPACK computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       Parameter adjustments */+    --z__;++    /* Function Body */+    if (*n0 - *i0 - 1 <= 0) {+	return 0;+    }++    dthresh = *eps * (*sigma + *tau);+    if (*tau < dthresh * .5) {+	*tau = 0.;+    }+    if (*tau != 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);++	}+    } else {+/*     This is the version that sets d's to zero if they are small enough */+	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;+		    if (d__ < dthresh) {+			d__ = 0.;+		    }+		    *dmin__ = min(*dmin__,d__);+		    z__[j4] = z__[j4 - 1] * temp;+/* Computing MIN */+		    d__1 = z__[j4];+		    emin = min(d__1,emin);+/* L50: */+		}+	    } 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;+		    if (d__ < dthresh) {+			d__ = 0.;+		    }+		    *dmin__ = min(*dmin__,d__);+		    z__[j4 - 1] = z__[j4] * temp;+/* Computing MIN */+		    d__1 = z__[j4 - 1];+		    emin = min(d__1,emin);+/* L60: */+		}+	    }++/*     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;+		    }+		    if (d__ < dthresh) {+			d__ = 0.;+		    }+		    *dmin__ = min(*dmin__,d__);+/* Computing MIN */+		    d__1 = emin, d__2 = z__[j4];+		    emin = min(d__1,d__2);+/* L70: */+		}+	    } 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;+		    }+		    if (d__ < dthresh) {+			d__ = 0.;+		    }+		    *dmin__ = min(*dmin__,d__);+/* Computing MIN */+		    d__1 = emin, d__2 = z__[j4 - 1];+		    emin = min(d__1,d__2);+/* L80: */+		}+	    }++/*     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_ */+
+ igraph/src/dlasq6.c view
@@ -0,0 +1,271 @@+/*  -- 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"++/* > \brief \b DLASQ6 computes one dqd transform in ping-pong form. Used by sbdsqr and sstegr.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASQ6 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasq6.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasq6.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasq6.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASQ6( I0, N0, Z, PP, DMIN, DMIN1, DMIN2, DN,   +                            DNM1, DNM2 )   ++         INTEGER            I0, N0, PP   +         DOUBLE PRECISION   DMIN, DMIN1, DMIN2, DN, DNM1, DNM2   +         DOUBLE PRECISION   Z( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DLASQ6 computes one dqd (shift equal to zero) transform in   +   > ping-pong form, with protection against underflow and overflow.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] I0   +   > \verbatim   +   >          I0 is INTEGER   +   >        First index.   +   > \endverbatim   +   >   +   > \param[in] N0   +   > \verbatim   +   >          N0 is INTEGER   +   >        Last index.   +   > \endverbatim   +   >   +   > \param[in] Z   +   > \verbatim   +   >          Z is DOUBLE PRECISION array, dimension ( 4*N )   +   >        Z holds the qd array. EMIN is stored in Z(4*N0) to avoid   +   >        an extra argument.   +   > \endverbatim   +   >   +   > \param[in] PP   +   > \verbatim   +   >          PP is INTEGER   +   >        PP=0 for ping, PP=1 for pong.   +   > \endverbatim   +   >   +   > \param[out] DMIN   +   > \verbatim   +   >          DMIN is DOUBLE PRECISION   +   >        Minimum value of d.   +   > \endverbatim   +   >   +   > \param[out] DMIN1   +   > \verbatim   +   >          DMIN1 is DOUBLE PRECISION   +   >        Minimum value of d, excluding D( N0 ).   +   > \endverbatim   +   >   +   > \param[out] DMIN2   +   > \verbatim   +   >          DMIN2 is DOUBLE PRECISION   +   >        Minimum value of d, excluding D( N0 ) and D( N0-1 ).   +   > \endverbatim   +   >   +   > \param[out] DN   +   > \verbatim   +   >          DN is DOUBLE PRECISION   +   >        d(N0), the last value of d.   +   > \endverbatim   +   >   +   > \param[out] DNM1   +   > \verbatim   +   >          DNM1 is DOUBLE PRECISION   +   >        d(N0-1).   +   > \endverbatim   +   >   +   > \param[out] DNM2   +   > \verbatim   +   >          DNM2 is DOUBLE PRECISION   +   >        d(N0-2).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlasr.c view
@@ -0,0 +1,512 @@+/*  -- 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"++/* > \brief \b DLASR applies a sequence of plane rotations to a general rectangular matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasr.f+">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasr.f+">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasr.f+">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASR( SIDE, PIVOT, DIRECT, M, N, C, S, A, LDA )   ++         CHARACTER          DIRECT, PIVOT, SIDE   +         INTEGER            LDA, M, N   +         DOUBLE PRECISION   A( LDA, * ), C( * ), S( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is 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   +   > \endverbatim   +   >   +   > \param[in] PIVOT   +   > \verbatim   +   >          PIVOT is 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)   +   > \endverbatim   +   >   +   > \param[in] DIRECT   +   > \verbatim   +   >          DIRECT is 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)   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.  If m <= 1, an immediate   +   >          return is effected.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.  If n <= 1, an   +   >          immediate return is effected.   +   > \endverbatim   +   >   +   > \param[in] C   +   > \verbatim   +   >          C is DOUBLE PRECISION array, dimension   +   >                  (M-1) if SIDE = 'L'   +   >                  (N-1) if SIDE = 'R'   +   >          The cosines c(k) of the plane rotations.   +   > \endverbatim   +   >   +   > \param[in] S   +   > \verbatim   +   >          S is 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) ).   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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'.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,M).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlasrt.c view
@@ -0,0 +1,330 @@+/*  -- 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"++/* > \brief \b DLASRT sorts numbers in increasing or decreasing order.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASRT + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasrt.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasrt.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasrt.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASRT( ID, N, D, INFO )   ++         CHARACTER          ID   +         INTEGER            INFO, N   +         DOUBLE PRECISION   D( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] ID   +   > \verbatim   +   >          ID is CHARACTER*1   +   >          = 'I': sort D in increasing order;   +   >          = 'D': sort D in decreasing order.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The length of the array D.   +   > \endverbatim   +   >   +   > \param[in,out] D   +   > \verbatim   +   >          D is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dlassq.c view
@@ -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"++/* > \brief \b DLASSQ updates a sum of squares represented in scaled form.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASSQ + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlassq.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlassq.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlassq.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASSQ( N, X, INCX, SCALE, SUMSQ )   ++         INTEGER            INCX, N   +         DOUBLE PRECISION   SCALE, SUMSQ   +         DOUBLE PRECISION   X( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of elements to be used from the vector X.   +   > \endverbatim   +   >   +   > \param[in] X   +   > \verbatim   +   >          X is 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.   +   > \endverbatim   +   >   +   > \param[in] INCX   +   > \verbatim   +   >          INCX is INTEGER   +   >          The increment between successive values of the vector X.   +   >          INCX > 0.   +   > \endverbatim   +   >   +   > \param[in,out] SCALE   +   > \verbatim   +   >          SCALE is 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.   +   > \endverbatim   +   >   +   > \param[in,out] SUMSQ   +   > \verbatim   +   >          SUMSQ is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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;+    extern logical igraphdisnan_(doublereal *);+++/*  -- LAPACK auxiliary routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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) {+	    absxi = (d__1 = x[ix], abs(d__1));+	    if (absxi > 0. || igraphdisnan_(&absxi)) {+		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_ */+
+ igraph/src/dlaswp.c view
@@ -0,0 +1,222 @@+/*  -- 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"++/* > \brief \b DLASWP performs a series of row interchanges on a general rectangular matrix.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASWP + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlaswp.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlaswp.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlaswp.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASWP( N, A, LDA, K1, K2, IPIV, INCX )   ++         INTEGER            INCX, K1, K2, LDA, N   +         INTEGER            IPIV( * )   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.   +   > \endverbatim   +   >   +   > \param[in] K1   +   > \verbatim   +   >          K1 is INTEGER   +   >          The first element of IPIV for which a row interchange will   +   >          be done.   +   > \endverbatim   +   >   +   > \param[in] K2   +   > \verbatim   +   >          K2 is INTEGER   +   >          The last element of IPIV for which a row interchange will   +   >          be done.   +   > \endverbatim   +   >   +   > \param[in] IPIV   +   > \verbatim   +   >          IPIV is 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.   +   > \endverbatim   +   >   +   > \param[in] INCX   +   > \verbatim   +   >          INCX is INTEGER   +   >          The increment between successive values of IPIV.  If IPIV   +   >          is negative, the pivots are applied in reverse order.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  Modified by   +   >   R. C. Whaley, Computer Science Dept., Univ. of Tenn., Knoxville, USA   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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_ */+
+ igraph/src/dlasy2.c view
@@ -0,0 +1,557 @@+/*  -- 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;++/* > \brief \b DLASY2 solves the Sylvester matrix equation where the matrices are of order 1 or 2.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLASY2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlasy2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlasy2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlasy2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLASY2( LTRANL, LTRANR, ISGN, N1, N2, TL, LDTL, TR,   +                            LDTR, B, LDB, SCALE, X, LDX, XNORM, INFO )   ++         LOGICAL            LTRANL, LTRANR   +         INTEGER            INFO, ISGN, LDB, LDTL, LDTR, LDX, N1, N2   +         DOUBLE PRECISION   SCALE, XNORM   +         DOUBLE PRECISION   B( LDB, * ), TL( LDTL, * ), TR( LDTR, * ),   +        $                   X( LDX, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] LTRANL   +   > \verbatim   +   >          LTRANL is LOGICAL   +   >          On entry, LTRANL specifies the op(TL):   +   >             = .FALSE., op(TL) = TL,   +   >             = .TRUE., op(TL) = TL**T.   +   > \endverbatim   +   >   +   > \param[in] LTRANR   +   > \verbatim   +   >          LTRANR is LOGICAL   +   >          On entry, LTRANR specifies the op(TR):   +   >            = .FALSE., op(TR) = TR,   +   >            = .TRUE., op(TR) = TR**T.   +   > \endverbatim   +   >   +   > \param[in] ISGN   +   > \verbatim   +   >          ISGN is INTEGER   +   >          On entry, ISGN specifies the sign of the equation   +   >          as described before. ISGN may only be 1 or -1.   +   > \endverbatim   +   >   +   > \param[in] N1   +   > \verbatim   +   >          N1 is INTEGER   +   >          On entry, N1 specifies the order of matrix TL.   +   >          N1 may only be 0, 1 or 2.   +   > \endverbatim   +   >   +   > \param[in] N2   +   > \verbatim   +   >          N2 is INTEGER   +   >          On entry, N2 specifies the order of matrix TR.   +   >          N2 may only be 0, 1 or 2.   +   > \endverbatim   +   >   +   > \param[in] TL   +   > \verbatim   +   >          TL is DOUBLE PRECISION array, dimension (LDTL,2)   +   >          On entry, TL contains an N1 by N1 matrix.   +   > \endverbatim   +   >   +   > \param[in] LDTL   +   > \verbatim   +   >          LDTL is INTEGER   +   >          The leading dimension of the matrix TL. LDTL >= max(1,N1).   +   > \endverbatim   +   >   +   > \param[in] TR   +   > \verbatim   +   >          TR is DOUBLE PRECISION array, dimension (LDTR,2)   +   >          On entry, TR contains an N2 by N2 matrix.   +   > \endverbatim   +   >   +   > \param[in] LDTR   +   > \verbatim   +   >          LDTR is INTEGER   +   >          The leading dimension of the matrix TR. LDTR >= max(1,N2).   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is DOUBLE PRECISION array, dimension (LDB,2)   +   >          On entry, the N1 by N2 matrix B contains the right-hand   +   >          side of the equation.   +   > \endverbatim   +   >   +   > \param[in] LDB   +   > \verbatim   +   >          LDB is INTEGER   +   >          The leading dimension of the matrix B. LDB >= max(1,N1).   +   > \endverbatim   +   >   +   > \param[out] SCALE   +   > \verbatim   +   >          SCALE is DOUBLE PRECISION   +   >          On exit, SCALE contains the scale factor. SCALE is chosen   +   >          less than or equal to 1 to prevent the solution overflowing.   +   > \endverbatim   +   >   +   > \param[out] X   +   > \verbatim   +   >          X is DOUBLE PRECISION array, dimension (LDX,2)   +   >          On exit, X contains the N1 by N2 solution.   +   > \endverbatim   +   >   +   > \param[in] LDX   +   > \verbatim   +   >          LDX is INTEGER   +   >          The leading dimension of the matrix X. LDX >= max(1,N1).   +   > \endverbatim   +   >   +   > \param[out] XNORM   +   > \verbatim   +   >          XNORM is DOUBLE PRECISION   +   >          On exit, XNORM is the infinity-norm of the solution.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleSYauxiliary   ++    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   ++       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_ */+
+ igraph/src/dlatrd.c view
@@ -0,0 +1,418 @@+/*  -- 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.;++/* > \brief \b DLATRD reduces the first nb rows and columns of a symmetric/Hermitian matrix A to real tridiago+nal form by an orthogonal similarity transformation.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DLATRD + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dlatrd.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dlatrd.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dlatrd.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DLATRD( UPLO, N, NB, A, LDA, E, TAU, W, LDW )   ++         CHARACTER          UPLO   +         INTEGER            LDA, LDW, N, NB   +         DOUBLE PRECISION   A( LDA, * ), E( * ), TAU( * ), W( LDW, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is CHARACTER*1   +   >          Specifies whether the upper or lower triangular part of the   +   >          symmetric matrix A is stored:   +   >          = 'U': Upper triangular   +   >          = 'L': Lower triangular   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.   +   > \endverbatim   +   >   +   > \param[in] NB   +   > \verbatim   +   >          NB is INTEGER   +   >          The number of rows and columns to be reduced.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= (1,N).   +   > \endverbatim   +   >   +   > \param[out] E   +   > \verbatim   +   >          E is 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.   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is 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.   +   > \endverbatim   +   >   +   > \param[out] W   +   > \verbatim   +   >          W is DOUBLE PRECISION array, dimension (LDW,NB)   +   >          The n-by-nb matrix W required to update the unreduced part   +   >          of A.   +   > \endverbatim   +   >   +   > \param[in] LDW   +   > \verbatim   +   >          LDW is INTEGER   +   >          The leading dimension of the array W. LDW >= max(1,N).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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).   +   > \endverbatim   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dmout.c view
@@ -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_ */+
+ igraph/src/dnaitr.c view
@@ -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 = 0, t3, t4, t5;+    integer jj;+    IGRAPH_F77_SAVE integer ipj, irj;+    integer nbx = 0;+    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 = 0;+    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 = 0;+    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, ndigit, nitref = 0, mnaitr = 0;+    real titref = 0, tnaitr = 0;+    IGRAPH_F77_SAVE integer msglvl;+    IGRAPH_F77_SAVE doublereal smlnum;+    integer nrorth = 0;+    IGRAPH_F77_SAVE logical rstart;+    integer nrstrt = 0;+    real tmvopx = 0;+++/*     %----------------------------------------------------%   +       | 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_ */+
+ igraph/src/dnapps.c view
@@ -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, ndigit;+    doublereal sigmar;+    integer mnapps = 0, msglvl;+    real tnapps = 0.;+    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_ */+
+ igraph/src/dnaup2.c view
@@ -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;+    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, 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_ */+
+ igraph/src/dnaupd.c view
@@ -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 = 0;+    IGRAPH_F77_SAVE integer nev0, mode;+    integer ierr;+    IGRAPH_F77_SAVE integer iupd, next;+    integer nopx = 0;+    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, 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 = 0, nrstrt = 0;+    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_ */+
+ igraph/src/dnconv.c view
@@ -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 = 0.;+++/*     %----------------------------------------------------%   +       | 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_ */+
+ igraph/src/dneigh.c view
@@ -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, ndigit;+    logical select[1];+    real tneigh = 0.;+    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_ */+
+ igraph/src/dneupd.c view
@@ -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, 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_ */+
+ igraph/src/dngets.c view
@@ -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, ndigit, mngets = 0;+    extern /* Subroutine */ int igraphdsortc_(char *, logical *, integer *, +	    doublereal *, doublereal *, doublereal *);+    integer msglvl;+    real tngets = 0.;+++/*     %----------------------------------------------------%   +       | 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_ */+
+ igraph/src/dnrm2.c view
@@ -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_ */+
+ igraph/src/dolio.c view
@@ -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
+ igraph/src/dorg2r.c view
@@ -0,0 +1,233 @@+/*  -- 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;++/* > \brief \b DORG2R generates all or part of the orthogonal matrix Q from a QR factorization determined by s+geqrf (unblocked algorithm).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORG2R + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dorg2r.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dorg2r.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dorg2r.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORG2R( M, N, K, A, LDA, TAU, WORK, INFO )   ++         INTEGER            INFO, K, LDA, M, N   +         DOUBLE PRECISION   A( LDA, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix Q. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix Q. M >= N >= 0.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The number of elementary reflectors whose product defines the   +   >          matrix Q. N >= K >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The first dimension of the array A. LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (K)   +   >          TAU(i) must contain the scalar factor of the elementary   +   >          reflector H(i), as returned by DGEQRF.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0: successful exit   +   >          < 0: if INFO = -i, the i-th argument has an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dorghr.c view
@@ -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;+static integer c_n1 = -1;++/* > \brief \b DORGHR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORGHR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dorghr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dorghr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dorghr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORGHR( N, ILO, IHI, A, LDA, TAU, WORK, LWORK, INFO )   ++         INTEGER            IHI, ILO, INFO, LDA, LWORK, N   +         DOUBLE PRECISION   A( LDA, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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).   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix Q. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A. LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (N-1)   +   >          TAU(i) must contain the scalar factor of the elementary   +   >          reflector H(i), as returned by DGEHRD.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dorgqr.c view
@@ -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 integer c__1 = 1;+static integer c_n1 = -1;+static integer c__3 = 3;+static integer c__2 = 2;++/* > \brief \b DORGQR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORGQR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dorgqr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dorgqr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dorgqr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORGQR( M, N, K, A, LDA, TAU, WORK, LWORK, INFO )   ++         INTEGER            INFO, K, LDA, LWORK, M, N   +         DOUBLE PRECISION   A( LDA, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix Q. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix Q. M >= N >= 0.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The number of elementary reflectors whose product defines the   +   >          matrix Q. N >= K >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The first dimension of the array A. LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (K)   +   >          TAU(i) must contain the scalar factor of the elementary   +   >          reflector H(i), as returned by DGEQRF.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument has an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dorm2l.c view
@@ -0,0 +1,301 @@+/*  -- 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;++/* > \brief \b DORM2L multiplies a general matrix by the orthogonal matrix from a QL factorization determined +by sgeqlf (unblocked algorithm).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORM2L + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dorm2l.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dorm2l.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dorm2l.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORM2L( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,   +                            WORK, INFO )   ++         CHARACTER          SIDE, TRANS   +         INTEGER            INFO, K, LDA, LDC, M, N   +         DOUBLE PRECISION   A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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'.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': apply Q or Q**T from the Left   +   >          = 'R': apply Q or Q**T from the Right   +   > \endverbatim   +   >   +   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is CHARACTER*1   +   >          = 'N': apply Q  (No transpose)   +   >          = 'T': apply Q**T (Transpose)   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The number of elementary reflectors whose product defines   +   >          the matrix Q.   +   >          If SIDE = 'L', M >= K >= 0;   +   >          if SIDE = 'R', N >= K >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.   +   >          If SIDE = 'L', LDA >= max(1,M);   +   >          if SIDE = 'R', LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (K)   +   >          TAU(i) must contain the scalar factor of the elementary   +   >          reflector H(i), as returned by DGEQLF.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension   +   >                                   (N) if SIDE = 'L',   +   >                                   (M) if SIDE = 'R'   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0: successful exit   +   >          < 0: if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dorm2r.c view
@@ -0,0 +1,305 @@+/*  -- 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;++/* > \brief \b DORM2R multiplies a general matrix by the orthogonal matrix from a QR factorization determined +by sgeqrf (unblocked algorithm).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORM2R + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dorm2r.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dorm2r.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dorm2r.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORM2R( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,   +                            WORK, INFO )   ++         CHARACTER          SIDE, TRANS   +         INTEGER            INFO, K, LDA, LDC, M, N   +         DOUBLE PRECISION   A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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'.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': apply Q or Q**T from the Left   +   >          = 'R': apply Q or Q**T from the Right   +   > \endverbatim   +   >   +   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is CHARACTER*1   +   >          = 'N': apply Q  (No transpose)   +   >          = 'T': apply Q**T (Transpose)   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The number of elementary reflectors whose product defines   +   >          the matrix Q.   +   >          If SIDE = 'L', M >= K >= 0;   +   >          if SIDE = 'R', N >= K >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.   +   >          If SIDE = 'L', LDA >= max(1,M);   +   >          if SIDE = 'R', LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (K)   +   >          TAU(i) must contain the scalar factor of the elementary   +   >          reflector H(i), as returned by DGEQRF.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension   +   >                                   (N) if SIDE = 'L',   +   >                                   (M) if SIDE = 'R'   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0: successful exit   +   >          < 0: if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dormhr.c view
@@ -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"++/* Table of constant values */++static integer c__1 = 1;+static integer c_n1 = -1;+static integer c__2 = 2;++/* > \brief \b DORMHR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORMHR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dormhr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dormhr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dormhr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORMHR( SIDE, TRANS, M, N, ILO, IHI, A, LDA, TAU, C,   +                            LDC, WORK, LWORK, INFO )   ++         CHARACTER          SIDE, TRANS   +         INTEGER            IHI, ILO, INFO, LDA, LDC, LWORK, M, N   +         DOUBLE PRECISION   A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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).   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': apply Q or Q**T from the Left;   +   >          = 'R': apply Q or Q**T from the Right.   +   > \endverbatim   +   >   +   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is CHARACTER*1   +   >          = 'N':  No transpose, apply Q;   +   >          = 'T':  Transpose, apply Q**T.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is 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.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.   +   >          LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'.   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is 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.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dormql.c view
@@ -0,0 +1,398 @@+/*  -- 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;++/* > \brief \b DORMQL   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORMQL + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dormql.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dormql.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dormql.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORMQL( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,   +                            WORK, LWORK, INFO )   ++         CHARACTER          SIDE, TRANS   +         INTEGER            INFO, K, LDA, LDC, LWORK, M, N   +         DOUBLE PRECISION   A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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'.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': apply Q or Q**T from the Left;   +   >          = 'R': apply Q or Q**T from the Right.   +   > \endverbatim   +   >   +   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is CHARACTER*1   +   >          = 'N':  No transpose, apply Q;   +   >          = 'T':  Transpose, apply Q**T.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The number of elementary reflectors whose product defines   +   >          the matrix Q.   +   >          If SIDE = 'L', M >= K >= 0;   +   >          if SIDE = 'R', N >= K >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.   +   >          If SIDE = 'L', LDA >= max(1,M);   +   >          if SIDE = 'R', LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (K)   +   >          TAU(i) must contain the scalar factor of the elementary   +   >          reflector H(i), as returned by DGEQLF.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dormqr.c view
@@ -0,0 +1,398 @@+/*  -- 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;++/* > \brief \b DORMQR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORMQR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dormqr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dormqr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dormqr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORMQR( SIDE, TRANS, M, N, K, A, LDA, TAU, C, LDC,   +                            WORK, LWORK, INFO )   ++         CHARACTER          SIDE, TRANS   +         INTEGER            INFO, K, LDA, LDC, LWORK, M, N   +         DOUBLE PRECISION   A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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'.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': apply Q or Q**T from the Left;   +   >          = 'R': apply Q or Q**T from the Right.   +   > \endverbatim   +   >   +   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is CHARACTER*1   +   >          = 'N':  No transpose, apply Q;   +   >          = 'T':  Transpose, apply Q**T.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] K   +   > \verbatim   +   >          K is INTEGER   +   >          The number of elementary reflectors whose product defines   +   >          the matrix Q.   +   >          If SIDE = 'L', M >= K >= 0;   +   >          if SIDE = 'R', N >= K >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.   +   >          If SIDE = 'L', LDA >= max(1,M);   +   >          if SIDE = 'R', LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (K)   +   >          TAU(i) must contain the scalar factor of the elementary   +   >          reflector H(i), as returned by DGEQRF.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dormtr.c view
@@ -0,0 +1,373 @@+/*  -- 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;++/* > \brief \b DORMTR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DORMTR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dormtr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dormtr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dormtr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DORMTR( SIDE, UPLO, TRANS, M, N, A, LDA, TAU, C, LDC,   +                            WORK, LWORK, INFO )   ++         CHARACTER          SIDE, TRANS, UPLO   +         INTEGER            INFO, LDA, LDC, LWORK, M, N   +         DOUBLE PRECISION   A( LDA, * ), C( LDC, * ), TAU( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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).   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'L': apply Q or Q**T from the Left;   +   >          = 'R': apply Q or Q**T from the Right.   +   > \endverbatim   +   >   +   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is CHARACTER*1   +   >          = 'U': Upper triangle of A contains elementary reflectors   +   >                 from DSYTRD;   +   >          = 'L': Lower triangle of A contains elementary reflectors   +   >                 from DSYTRD.   +   > \endverbatim   +   >   +   > \param[in] TRANS   +   > \verbatim   +   >          TRANS is CHARACTER*1   +   >          = 'N':  No transpose, apply Q;   +   >          = 'T':  Transpose, apply Q**T.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix C. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix C. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.   +   >          LDA >= max(1,M) if SIDE = 'L'; LDA >= max(1,N) if SIDE = 'R'.   +   > \endverbatim   +   >   +   > \param[in] TAU   +   > \verbatim   +   >          TAU is 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.   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dotproduct.c view
@@ -0,0 +1,280 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_games.h"+#include "igraph_random.h"+#include "igraph_constructors.h"+#include "igraph_lapack.h"++/**+ * \function igraph_dot_product_game+ * Generate a random dot product graph+ *+ * In this model, each vertex is represented by a latent+ * position vector. Probability of an edge between two vertices are given+ * by the dot product of their latent position vectors.+ *+ * </para><para>+ * See also Christine Leigh Myers Nickel: Random dot product graphs, a+ * model for social networks. Dissertation, Johns Hopkins University,+ * Maryland, USA, 2006.+ *+ * \param graph The output graph is stored here.+ * \param vecs A matrix in which each latent position vector is a+ *    column. The dot product of the latent position vectors should be+ *    in the [0,1] interval, otherwise a warning is given. For+ *    negative dot products, no edges are added; dot products that are+ *    larger than one always add an edge.+ * \param directed Should the generated graph be directed?+ * \return Error code.+ *+ * Time complexity: O(n*n*m), where n is the number of vertices,+ * and m is the length of the latent vectors.+ *+ * \sa \ref igraph_sample_dirichlet(), \ref+ * igraph_sample_sphere_volume(), \ref igraph_sample_sphere_surface()+ * for functions to generate the latent vectors.+ */++int igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *vecs,+                            igraph_bool_t directed) {++    igraph_integer_t nrow = igraph_matrix_nrow(vecs);+    igraph_integer_t ncol = igraph_matrix_ncol(vecs);+    int i, j;+    igraph_vector_t edges;+    igraph_bool_t warned_neg = 0, warned_big = 0;++    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);++    RNG_BEGIN();++    for (i = 0; i < ncol; i++) {+        int from = directed ? 0 : i + 1;+        igraph_vector_t v1;+        igraph_vector_view(&v1, &MATRIX(*vecs, 0, i), nrow);+        for (j = from; j < ncol; j++) {+            igraph_real_t prob;+            igraph_vector_t v2;+            if (i == j) {+                continue;+            }+            igraph_vector_view(&v2, &MATRIX(*vecs, 0, j), nrow);+            igraph_lapack_ddot(&v1, &v2, &prob);+            if (prob < 0 && ! warned_neg) {+                warned_neg = 1;+                IGRAPH_WARNING("Negative connection probability in "+                               "dot-product graph");+            } else if (prob > 1 && ! warned_big) {+                warned_big = 1;+                IGRAPH_WARNING("Greater than 1 connection probability in "+                               "dot-product graph");+                IGRAPH_CHECK(igraph_vector_push_back(&edges, i));+                IGRAPH_CHECK(igraph_vector_push_back(&edges, j));+            } else if (RNG_UNIF01() < prob) {+                IGRAPH_CHECK(igraph_vector_push_back(&edges, i));+                IGRAPH_CHECK(igraph_vector_push_back(&edges, j));+            }+        }+    }++    RNG_END();++    igraph_create(graph, &edges, ncol, directed);+    igraph_vector_destroy(&edges);+    IGRAPH_FINALLY_CLEAN(1);++    return 0;+}++/**+ * \function igraph_sample_sphere_surface+ * Sample points uniformly from the surface of a sphere+ *+ * The center of the sphere is at the origin.+ *+ * \param dim The dimension of the random vectors.+ * \param n The number of vectors to sample.+ * \param radius Radius of the sphere, it must be positive.+ * \param positive Whether to restrict sampling to the positive+ *    orthant.+ * \param res Pointer to an initialized matrix, the result is+ *    stored here, each column will be a sampled vector. The matrix is+ *    resized, as needed.+ * \return Error code.+ *+ * Time complexity: O(n*dim*g), where g is the time complexity of+ * generating a standard normal random number.+ *+ * \sa \ref igraph_sample_sphere_volume(), \ref+ * igraph_sample_dirichlet() for other similar samplers.+ */++int igraph_sample_sphere_surface(igraph_integer_t dim, igraph_integer_t n,+                                 igraph_real_t radius,+                                 igraph_bool_t positive,+                                 igraph_matrix_t *res) {+    igraph_integer_t i, j;++    if (dim < 2) {+        IGRAPH_ERROR("Sphere must be at least two dimensional to sample from "+                     "surface", IGRAPH_EINVAL);+    }+    if (n < 0) {+        IGRAPH_ERROR("Number of samples must be non-negative", IGRAPH_EINVAL);+    }+    if (radius <= 0) {+        IGRAPH_ERROR("Sphere radius must be positive", IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_matrix_resize(res, dim, n));++    RNG_BEGIN();++    for (i = 0; i < n; i++) {+        igraph_real_t *col = &MATRIX(*res, 0, i);+        igraph_real_t sum = 0.0;+        for (j = 0; j < dim; j++) {+            col[j] = RNG_NORMAL(0, 1);+            sum += col[j] * col[j];+        }+        sum = sqrt(sum);+        for (j = 0; j < dim; j++) {+            col[j] = radius * col[j] / sum;+        }+        if (positive) {+            for (j = 0; j < dim; j++) {+                col[j] = fabs(col[j]);+            }+        }+    }++    RNG_END();++    return 0;+}++/**+ * \function igraph_sample_sphere_volume+ * Sample points uniformly from the volume of a sphere+ *+ * The center of the sphere is at the origin.+ *+ * \param dim The dimension of the random vectors.+ * \param n The number of vectors to sample.+ * \param radius Radius of the sphere, it must be positive.+ * \param positive Whether to restrict sampling to the positive+ *    orthant.+ * \param res Pointer to an initialized matrix, the result is+ *    stored here, each column will be a sampled vector. The matrix is+ *    resized, as needed.+ * \return Error code.+ *+ * Time complexity: O(n*dim*g), where g is the time complexity of+ * generating a standard normal random number.+ *+ * \sa \ref igraph_sample_sphere_surface(), \ref+ * igraph_sample_dirichlet() for other similar samplers.+ */+++int igraph_sample_sphere_volume(igraph_integer_t dim, igraph_integer_t n,+                                igraph_real_t radius,+                                igraph_bool_t positive,+                                igraph_matrix_t *res) {++    igraph_integer_t i, j;++    /* Arguments are checked by the following call */++    IGRAPH_CHECK(igraph_sample_sphere_surface(dim, n, radius, positive, res));++    RNG_BEGIN();++    for (i = 0; i < n; i++) {+        igraph_real_t *col = &MATRIX(*res, 0, i);+        igraph_real_t U = pow(RNG_UNIF01(), 1.0 / dim);+        for (j = 0; j < dim; j++) {+            col[j] *= U;+        }+    }++    RNG_END();++    return 0;+}++/**+ * \function igraph_sample_dirichlet+ * Sample points from a Dirichlet distribution+ *+ * \param n The number of vectors to sample.+ * \param alpha The parameters of the Dirichlet distribution. They+ *    must be positive. The length of this vector gives the dimension+ *    of the generated samples.+ * \param res Pointer to an initialized matrix, the result is stored+ *    here, one sample in each column. It will be resized, as needed.+ * \return Error code.+ *+ * Time complexity: O(n * dim * g), where dim is the dimension of the+ * sample vectors, set by the length of alpha, and g is the time+ * complexity of sampling from a Gamma distribution.+ *+ * \sa \ref igraph_sample_sphere_surface() and+ * \ref igraph_sample_sphere_volume() for other methods to sample+ * latent vectors.+ */++int igraph_sample_dirichlet(igraph_integer_t n, const igraph_vector_t *alpha,+                            igraph_matrix_t *res) {++    igraph_integer_t len = igraph_vector_size(alpha);+    igraph_integer_t i;+    igraph_vector_t vec;++    if (n < 0) {+        IGRAPH_ERROR("Number of samples should be non-negative",+                     IGRAPH_EINVAL);+    }+    if (len < 2) {+        IGRAPH_ERROR("Dirichlet parameter vector too short, must "+                     "have at least two entries", IGRAPH_EINVAL);+    }+    if (igraph_vector_min(alpha) <= 0) {+        IGRAPH_ERROR("Dirichlet concentration parameters must be positive",+                     IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_matrix_resize(res, len, n));++    RNG_BEGIN();++    for (i = 0; i < n; i++) {+        igraph_vector_view(&vec, &MATRIX(*res, 0, i), len);+        igraph_rng_get_dirichlet(igraph_rng_default(), alpha, &vec);+    }++    RNG_END();++    return 0;+}
+ igraph/src/dpotf2.c view
@@ -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"++/* Table of constant values */++static integer c__1 = 1;+static doublereal c_b10 = -1.;+static doublereal c_b12 = 1.;++/* > \brief \b DPOTF2 computes the Cholesky factorization of a symmetric/Hermitian positive definite matrix (u+nblocked algorithm).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DPOTF2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dpotf2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dpotf2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dpotf2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DPOTF2( UPLO, N, A, LDA, INFO )   ++         CHARACTER          UPLO   +         INTEGER            INFO, LDA, N   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DPOTF2 computes the Cholesky factorization of a real symmetric   +   > positive definite matrix A.   +   >   +   > The factorization has the form   +   >    A = U**T * U ,  if UPLO = 'U', or   +   >    A = L  * L**T,  if UPLO = 'L',   +   > where U is an upper triangular matrix and L is lower triangular.   +   >   +   > This is the unblocked version of the algorithm, calling Level 2 BLAS.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is CHARACTER*1   +   >          Specifies whether the upper or lower triangular part of the   +   >          symmetric matrix A is stored.   +   >          = 'U':  Upper triangular   +   >          = 'L':  Lower triangular   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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 INFO = 0, the factor U or L from the Cholesky   +   >          factorization A = U**T *U  or A = L*L**T.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0: successful exit   +   >          < 0: if INFO = -k, the k-th argument had an illegal value   +   >          > 0: if INFO = k, the leading minor of order k is not   +   >               positive definite, and the factorization could not be   +   >               completed.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doublePOcomputational   ++    =====================================================================   +   Subroutine */ int igraphdpotf2_(char *uplo, integer *n, doublereal *a, integer *+	lda, integer *info)+{+    /* System generated locals */+    integer a_dim1, a_offset, i__1, i__2, i__3;+    doublereal d__1;++    /* Builtin functions */+    double sqrt(doublereal);++    /* Local variables */+    integer j;+    doublereal ajj;+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, +	    integer *);+    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 *);+    logical upper;+    extern logical igraphdisnan_(doublereal *);+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);+++/*  -- LAPACK computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       Test the input parameters.   ++       Parameter adjustments */+    a_dim1 = *lda;+    a_offset = 1 + a_dim1;+    a -= a_offset;++    /* 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_("DPOTF2", &i__1, (ftnlen)6);+	return 0;+    }++/*     Quick return if possible */++    if (*n == 0) {+	return 0;+    }++    if (upper) {++/*        Compute the Cholesky factorization A = U**T *U. */++	i__1 = *n;+	for (j = 1; j <= i__1; ++j) {++/*           Compute U(J,J) and test for non-positive-definiteness. */++	    i__2 = j - 1;+	    ajj = a[j + j * a_dim1] - igraphddot_(&i__2, &a[j * a_dim1 + 1], &c__1, +		    &a[j * a_dim1 + 1], &c__1);+	    if (ajj <= 0. || igraphdisnan_(&ajj)) {+		a[j + j * a_dim1] = ajj;+		goto L30;+	    }+	    ajj = sqrt(ajj);+	    a[j + j * a_dim1] = ajj;++/*           Compute elements J+1:N of row J. */++	    if (j < *n) {+		i__2 = j - 1;+		i__3 = *n - j;+		igraphdgemv_("Transpose", &i__2, &i__3, &c_b10, &a[(j + 1) * a_dim1 +			+ 1], lda, &a[j * a_dim1 + 1], &c__1, &c_b12, &a[j + (+			j + 1) * a_dim1], lda);+		i__2 = *n - j;+		d__1 = 1. / ajj;+		igraphdscal_(&i__2, &d__1, &a[j + (j + 1) * a_dim1], lda);+	    }+/* L10: */+	}+    } else {++/*        Compute the Cholesky factorization A = L*L**T. */++	i__1 = *n;+	for (j = 1; j <= i__1; ++j) {++/*           Compute L(J,J) and test for non-positive-definiteness. */++	    i__2 = j - 1;+	    ajj = a[j + j * a_dim1] - igraphddot_(&i__2, &a[j + a_dim1], lda, &a[j +		    + a_dim1], lda);+	    if (ajj <= 0. || igraphdisnan_(&ajj)) {+		a[j + j * a_dim1] = ajj;+		goto L30;+	    }+	    ajj = sqrt(ajj);+	    a[j + j * a_dim1] = ajj;++/*           Compute elements J+1:N of column J. */++	    if (j < *n) {+		i__2 = *n - j;+		i__3 = j - 1;+		igraphdgemv_("No transpose", &i__2, &i__3, &c_b10, &a[j + 1 + +			a_dim1], lda, &a[j + a_dim1], lda, &c_b12, &a[j + 1 + +			j * a_dim1], &c__1);+		i__2 = *n - j;+		d__1 = 1. / ajj;+		igraphdscal_(&i__2, &d__1, &a[j + 1 + j * a_dim1], &c__1);+	    }+/* L20: */+	}+    }+    goto L40;++L30:+    *info = j;++L40:+    return 0;++/*     End of DPOTF2 */++} /* igraphdpotf2_ */+
+ igraph/src/dpotrf.c view
@@ -0,0 +1,293 @@+/*  -- 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_b13 = -1.;+static doublereal c_b14 = 1.;++/* > \brief \b DPOTRF   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DPOTRF + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dpotrf.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dpotrf.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dpotrf.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DPOTRF( UPLO, N, A, LDA, INFO )   ++         CHARACTER          UPLO   +         INTEGER            INFO, LDA, N   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DPOTRF computes the Cholesky factorization of a real symmetric   +   > positive definite matrix A.   +   >   +   > The factorization has the form   +   >    A = U**T * U,  if UPLO = 'U', or   +   >    A = L  * L**T,  if UPLO = 'L',   +   > where U is an upper triangular matrix and L is lower triangular.   +   >   +   > This is the block version of the algorithm, calling Level 3 BLAS.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is CHARACTER*1   +   >          = 'U':  Upper triangle of A is stored;   +   >          = 'L':  Lower triangle of A is stored.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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 INFO = 0, the factor U or L from the Cholesky   +   >          factorization A = U**T*U or A = L*L**T.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   >          > 0:  if INFO = i, the leading minor of order i is not   +   >                positive definite, and the factorization could not be   +   >                completed.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doublePOcomputational   ++    =====================================================================   +   Subroutine */ int igraphdpotrf_(char *uplo, integer *n, doublereal *a, integer *+	lda, integer *info)+{+    /* System generated locals */+    integer a_dim1, a_offset, i__1, i__2, i__3, i__4;++    /* Local variables */+    integer j, jb, nb;+    extern /* Subroutine */ int igraphdgemm_(char *, char *, integer *, integer *, +	    integer *, doublereal *, doublereal *, integer *, doublereal *, +	    integer *, doublereal *, doublereal *, integer *);+    extern logical igraphlsame_(char *, char *);+    extern /* Subroutine */ int igraphdtrsm_(char *, char *, char *, char *, +	    integer *, integer *, doublereal *, doublereal *, integer *, +	    doublereal *, integer *);+    logical upper;+    extern /* Subroutine */ int igraphdsyrk_(char *, char *, integer *, integer *, +	    doublereal *, doublereal *, integer *, doublereal *, doublereal *,+	     integer *), igraphdpotf2_(char *, integer *, +	    doublereal *, integer *, integer *), igraphxerbla_(char *, +	    integer *, ftnlen);+    extern integer igraphilaenv_(integer *, char *, char *, integer *, integer *, +	    integer *, integer *, ftnlen, ftnlen);+++/*  -- LAPACK computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       Test the input parameters.   ++       Parameter adjustments */+    a_dim1 = *lda;+    a_offset = 1 + a_dim1;+    a -= a_offset;++    /* 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_("DPOTRF", &i__1, (ftnlen)6);+	return 0;+    }++/*     Quick return if possible */++    if (*n == 0) {+	return 0;+    }++/*     Determine the block size for this environment. */++    nb = igraphilaenv_(&c__1, "DPOTRF", uplo, n, &c_n1, &c_n1, &c_n1, (ftnlen)6, (+	    ftnlen)1);+    if (nb <= 1 || nb >= *n) {++/*        Use unblocked code. */++	igraphdpotf2_(uplo, n, &a[a_offset], lda, info);+    } else {++/*        Use blocked code. */++	if (upper) {++/*           Compute the Cholesky factorization A = U**T*U. */++	    i__1 = *n;+	    i__2 = nb;+	    for (j = 1; i__2 < 0 ? j >= i__1 : j <= i__1; j += i__2) {++/*              Update and factorize the current diagonal block and test   +                for non-positive-definiteness.   ++   Computing MIN */+		i__3 = nb, i__4 = *n - j + 1;+		jb = min(i__3,i__4);+		i__3 = j - 1;+		igraphdsyrk_("Upper", "Transpose", &jb, &i__3, &c_b13, &a[j * +			a_dim1 + 1], lda, &c_b14, &a[j + j * a_dim1], lda);+		igraphdpotf2_("Upper", &jb, &a[j + j * a_dim1], lda, info);+		if (*info != 0) {+		    goto L30;+		}+		if (j + jb <= *n) {++/*                 Compute the current block row. */++		    i__3 = *n - j - jb + 1;+		    i__4 = j - 1;+		    igraphdgemm_("Transpose", "No transpose", &jb, &i__3, &i__4, &+			    c_b13, &a[j * a_dim1 + 1], lda, &a[(j + jb) * +			    a_dim1 + 1], lda, &c_b14, &a[j + (j + jb) * +			    a_dim1], lda);+		    i__3 = *n - j - jb + 1;+		    igraphdtrsm_("Left", "Upper", "Transpose", "Non-unit", &jb, &+			    i__3, &c_b14, &a[j + j * a_dim1], lda, &a[j + (j +			    + jb) * a_dim1], lda);+		}+/* L10: */+	    }++	} else {++/*           Compute the Cholesky factorization A = L*L**T. */++	    i__2 = *n;+	    i__1 = nb;+	    for (j = 1; i__1 < 0 ? j >= i__2 : j <= i__2; j += i__1) {++/*              Update and factorize the current diagonal block and test   +                for non-positive-definiteness.   ++   Computing MIN */+		i__3 = nb, i__4 = *n - j + 1;+		jb = min(i__3,i__4);+		i__3 = j - 1;+		igraphdsyrk_("Lower", "No transpose", &jb, &i__3, &c_b13, &a[j + +			a_dim1], lda, &c_b14, &a[j + j * a_dim1], lda);+		igraphdpotf2_("Lower", &jb, &a[j + j * a_dim1], lda, info);+		if (*info != 0) {+		    goto L30;+		}+		if (j + jb <= *n) {++/*                 Compute the current block column. */++		    i__3 = *n - j - jb + 1;+		    i__4 = j - 1;+		    igraphdgemm_("No transpose", "Transpose", &i__3, &jb, &i__4, &+			    c_b13, &a[j + jb + a_dim1], lda, &a[j + a_dim1], +			    lda, &c_b14, &a[j + jb + j * a_dim1], lda);+		    i__3 = *n - j - jb + 1;+		    igraphdtrsm_("Right", "Lower", "Transpose", "Non-unit", &i__3, &+			    jb, &c_b14, &a[j + j * a_dim1], lda, &a[j + jb + +			    j * a_dim1], lda);+		}+/* L20: */+	    }+	}+    }+    goto L40;++L30:+    *info = *info + j - 1;++L40:+    return 0;++/*     End of DPOTRF */++} /* igraphdpotrf_ */+
+ igraph/src/dqueue.c view
@@ -0,0 +1,55 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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++#define BASE_INT+#include "igraph_pmt.h"+#include "dqueue.pmt"+#include "igraph_pmt_off.h"+#undef BASE_INT
+ igraph/src/drl_graph.cpp view
@@ -0,0 +1,1309 @@+/*+ * 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
+ igraph/src/drl_graph_3d.cpp view
@@ -0,0 +1,877 @@+/*+ * 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
+ igraph/src/drl_layout.cpp view
@@ -0,0 +1,476 @@+/*+ * 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;++        break;+    default:+        IGRAPH_ERROR("Unknown 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. Originally,+ *    this argument was used in the DrL algorithm to keep the nodes marked+ *    with this argument as fixed; fixed nodes would then keep their+ *    positions in the initial stages of the algorithm. However, due to how+ *    the DrL code imported into igraph is organized, it seems that the+ *    argument does not do anything and we are not sure whether this is a+ *    bug or a feature in DrL. We are leaving the argument here in order not+ *    to break the API, but note that at the present stage it has no effect.+ * \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;+}
+ igraph/src/drl_layout_3d.cpp view
@@ -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;+}
+ igraph/src/drl_parse.cpp view
@@ -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
+ igraph/src/drot.c view
@@ -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_ */+
+ igraph/src/dsaitr.c view
@@ -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 = 0.0, t3, t4, t5;+    integer jj;+    IGRAPH_F77_SAVE integer ipj, irj;+    integer nbx = 0;+    IGRAPH_F77_SAVE integer ivj;+    extern doublereal igraphddot_(integer *, doublereal *, integer *, doublereal *, +	    integer *);+    IGRAPH_F77_SAVE integer ierr, iter;+    integer nopx = 0;+    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 = 0;+    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;+    IGRAPH_F77_SAVE doublereal safmin;+    integer ndigit = 0, nitref = 0;+    real titref = 0;+    integer msaitr = 0;+    IGRAPH_F77_SAVE integer msglvl;+    real tsaitr = 0;+    integer nrorth = 0;+    IGRAPH_F77_SAVE logical rstart;+    integer nrstrt = 0;+    real tmvopx = 0;+++/*     %----------------------------------------------------%   +       | 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_ */+
+ igraph/src/dsapps.c view
@@ -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, ndigit, msapps = 0, msglvl, istart;+    real tsapps = 0;+    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_ */+
+ igraph/src/dsaup2.c view
@@ -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 = 0;+    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 = 0.0;+    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, 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_ */+
+ igraph/src/dsaupd.c view
@@ -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 = 0;+    IGRAPH_F77_SAVE integer nev0, mode, ierr, iupd, next;+    integer nopx = 0;+    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, 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 = 0.0;+    IGRAPH_F77_SAVE integer mxiter;+    real tsgets, tsapps;+    integer nrorth = 0;+    real tsconv = 0.0;+    integer nrstrt = 0;+    real tmvopx = 0.0;++    /* 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_ */+
+ igraph/src/dscal.c view
@@ -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_ */+
+ igraph/src/dsconv.c view
@@ -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 = 0;+++/*     %----------------------------------------------------%   +       | 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_ */+
+ igraph/src/dseigt.c view
@@ -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, ndigit, mseigt = 0;+    extern /* Subroutine */ int igraphdstqrb_(integer *, doublereal *, doublereal *,+	     doublereal *, doublereal *, integer *);+    real tseigt = 0.0;+    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_ */+
+ igraph/src/dsesrt.c view
@@ -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_ */+
+ igraph/src/dseupd.c view
@@ -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, 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_ */+
+ igraph/src/dsgets.c view
@@ -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, ndigit, msgets = 0, msglvl;+    real tsgets = 0.0;+    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_ */+
+ igraph/src/dsortc.c view
@@ -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_ */+
+ igraph/src/dsortr.c view
@@ -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_ */+
+ igraph/src/dstatn.c view
@@ -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_ */+
+ igraph/src/dstats.c view
@@ -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_ */+
+ igraph/src/dstebz.c view
@@ -0,0 +1,867 @@+/*  -- 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;++/* > \brief \b DSTEBZ   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSTEBZ + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dstebz.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dstebz.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dstebz.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSTEBZ( RANGE, ORDER, N, VL, VU, IL, IU, ABSTOL, D, E,   +                            M, NSPLIT, W, IBLOCK, ISPLIT, WORK, IWORK,   +                            INFO )   ++         CHARACTER          ORDER, RANGE   +         INTEGER            IL, INFO, IU, M, N, NSPLIT   +         DOUBLE PRECISION   ABSTOL, VL, VU   +         INTEGER            IBLOCK( * ), ISPLIT( * ), IWORK( * )   +         DOUBLE PRECISION   D( * ), E( * ), W( * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] RANGE   +   > \verbatim   +   >          RANGE is 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.   +   > \endverbatim   +   >   +   > \param[in] ORDER   +   > \verbatim   +   >          ORDER is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the tridiagonal matrix T.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] VL   +   > \verbatim   +   >          VL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] VU   +   > \verbatim   +   >          VU is 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'.   +   > \endverbatim   +   >   +   > \param[in] IL   +   > \verbatim   +   >          IL is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IU   +   > \verbatim   +   >          IU is 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'.   +   > \endverbatim   +   >   +   > \param[in] ABSTOL   +   > \verbatim   +   >          ABSTOL is 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.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The n diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] E   +   > \verbatim   +   >          E is DOUBLE PRECISION array, dimension (N-1)   +   >          The (n-1) off-diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is INTEGER   +   >          The actual number of eigenvalues found. 0 <= M <= N.   +   >          (See also the description of INFO=2,3.)   +   > \endverbatim   +   >   +   > \param[out] NSPLIT   +   > \verbatim   +   >          NSPLIT is INTEGER   +   >          The number of diagonal blocks in the matrix T.   +   >          1 <= NSPLIT <= N.   +   > \endverbatim   +   >   +   > \param[out] W   +   > \verbatim   +   >          W is 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.)   +   > \endverbatim   +   >   +   > \param[out] IBLOCK   +   > \verbatim   +   >          IBLOCK is 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.)   +   > \endverbatim   +   >   +   > \param[out] ISPLIT   +   > \verbatim   +   >          ISPLIT is 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.)   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (4*N)   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (3*N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++   > \par Internal Parameters:   +    =========================   +   >   +   > \verbatim   +   >  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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dstein.c view
@@ -0,0 +1,525 @@+/*  -- 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;++/* > \brief \b DSTEIN   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSTEIN + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dstein.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dstein.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dstein.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSTEIN( N, D, E, M, W, IBLOCK, ISPLIT, Z, LDZ, WORK,   +                            IWORK, IFAIL, INFO )   ++         INTEGER            INFO, LDZ, M, N   +         INTEGER            IBLOCK( * ), IFAIL( * ), ISPLIT( * ),   +        $                   IWORK( * )   +         DOUBLE PRECISION   D( * ), E( * ), W( * ), WORK( * ), Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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).   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The n diagonal elements of the tridiagonal matrix T.   +   > \endverbatim   +   >   +   > \param[in] E   +   > \verbatim   +   >          E is DOUBLE PRECISION array, dimension (N-1)   +   >          The (n-1) subdiagonal elements of the tridiagonal matrix   +   >          T, in elements 1 to N-1.   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of eigenvectors to be found.  0 <= M <= N.   +   > \endverbatim   +   >   +   > \param[in] W   +   > \verbatim   +   >          W is 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. )   +   > \endverbatim   +   >   +   > \param[in] IBLOCK   +   > \verbatim   +   >          IBLOCK is 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. )   +   > \endverbatim   +   >   +   > \param[in] ISPLIT   +   > \verbatim   +   >          ISPLIT is 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. )   +   > \endverbatim   +   >   +   > \param[out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >          The leading dimension of the array Z.  LDZ >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (5*N)   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] IFAIL   +   > \verbatim   +   >          IFAIL is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++   > \par Internal Parameters:   +    =========================   +   >   +   > \verbatim   +   >  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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dstemr.c view
@@ -0,0 +1,831 @@+/*  -- 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;++/* > \brief \b DSTEMR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSTEMR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dstemr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dstemr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dstemr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSTEMR( JOBZ, RANGE, N, D, E, VL, VU, IL, IU,   +                            M, W, Z, LDZ, NZC, ISUPPZ, TRYRAC, WORK, LWORK,   +                            IWORK, LIWORK, INFO )   ++         CHARACTER          JOBZ, RANGE   +         LOGICAL            TRYRAC   +         INTEGER            IL, INFO, IU, LDZ, NZC, LIWORK, LWORK, M, N   +         DOUBLE PRECISION VL, VU   +         INTEGER            ISUPPZ( * ), IWORK( * )   +         DOUBLE PRECISION   D( * ), E( * ), W( * ), WORK( * )   +         DOUBLE PRECISION   Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOBZ   +   > \verbatim   +   >          JOBZ is CHARACTER*1   +   >          = 'N':  Compute eigenvalues only;   +   >          = 'V':  Compute eigenvalues and eigenvectors.   +   > \endverbatim   +   >   +   > \param[in] RANGE   +   > \verbatim   +   >          RANGE is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          On entry, the N diagonal elements of the tridiagonal matrix   +   >          T. On exit, D is overwritten.   +   > \endverbatim   +   >   +   > \param[in,out] E   +   > \verbatim   +   >          E is 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.   +   > \endverbatim   +   >   +   > \param[in] VL   +   > \verbatim   +   >          VL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] VU   +   > \verbatim   +   >          VU is 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'.   +   > \endverbatim   +   >   +   > \param[in] IL   +   > \verbatim   +   >          IL is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IU   +   > \verbatim   +   >          IU is 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'.   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is INTEGER   +   >          The total number of eigenvalues found.  0 <= M <= N.   +   >          If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.   +   > \endverbatim   +   >   +   > \param[out] W   +   > \verbatim   +   >          W is DOUBLE PRECISION array, dimension (N)   +   >          The first M elements contain the selected eigenvalues in   +   >          ascending order.   +   > \endverbatim   +   >   +   > \param[out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >          The leading dimension of the array Z.  LDZ >= 1, and if   +   >          JOBZ = 'V', then LDZ >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] NZC   +   > \verbatim   +   >          NZC is 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.   +   > \endverbatim   +   >   +   > \param[out] ISUPPZ   +   > \verbatim   +   >          ISUPPZ is 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.   +   > \endverbatim   +   >   +   > \param[in,out] TRYRAC   +   > \verbatim   +   >          TRYRAC is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (LWORK)   +   >          On exit, if INFO = 0, WORK(1) returns the optimal   +   >          (and minimal) LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (LIWORK)   +   >          On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.   +   > \endverbatim   +   >   +   > \param[in] LIWORK   +   > \verbatim   +   >          LIWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2013   ++   > \ingroup doubleOTHERcomputational   ++   > \par Contributors:   +    ==================   +   >   +   > Beresford Parlett, University of California, Berkeley, USA \n   +   > Jim Demmel, University of California, Berkeley, USA \n   +   > Inderjit Dhillon, University of Texas, Austin, USA \n   +   > Osni Marques, LBNL/NERSC, USA \n   +   > Christof Voemel, University of California, Berkeley, USA   ++    =====================================================================   +   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.5.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2013   +++    =====================================================================   +++       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;+    nsplit = 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;+		}+	    }+	}+    } else {+/*     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 || *n == 2) {+	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_ */+
+ igraph/src/dsteqr.c view
@@ -0,0 +1,677 @@+/*  -- 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;++/* > \brief \b DSTEQR   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSTEQR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dsteqr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dsteqr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dsteqr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSTEQR( COMPZ, N, D, E, Z, LDZ, WORK, INFO )   ++         CHARACTER          COMPZ   +         INTEGER            INFO, LDZ, N   +         DOUBLE PRECISION   D( * ), E( * ), WORK( * ), Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] COMPZ   +   > \verbatim   +   >          COMPZ is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          On entry, the diagonal elements of the tridiagonal matrix.   +   >          On exit, if INFO = 0, the eigenvalues in ascending order.   +   > \endverbatim   +   >   +   > \param[in,out] E   +   > \verbatim   +   >          E is DOUBLE PRECISION array, dimension (N-1)   +   >          On entry, the (n-1) subdiagonal elements of the tridiagonal   +   >          matrix.   +   >          On exit, E has been destroyed.   +   > \endverbatim   +   >   +   > \param[in,out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >          The leading dimension of the array Z.  LDZ >= 1, and if   +   >          eigenvectors are desired, then  LDZ >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (max(1,2*N-2))   +   >          If COMPZ = 'N', then WORK is not referenced.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dsterf.c view
@@ -0,0 +1,510 @@+/*  -- 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.;++/* > \brief \b DSTERF   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSTERF + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dsterf.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dsterf.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dsterf.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSTERF( N, D, E, INFO )   ++         INTEGER            INFO, N   +         DOUBLE PRECISION   D( * ), E( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DSTERF computes all eigenvalues of a symmetric tridiagonal matrix   +   > using the Pal-Walker-Kahan variant of the QL or QR algorithm.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] D   +   > \verbatim   +   >          D is 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.   +   > \endverbatim   +   >   +   > \param[in,out] E   +   > \verbatim   +   >          E is DOUBLE PRECISION array, dimension (N-1)   +   >          On entry, the (n-1) subdiagonal elements of the tridiagonal   +   >          matrix.   +   >          On exit, E has been destroyed.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dstqrb.c view
@@ -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_ */+
+ igraph/src/dswap.c view
@@ -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_ */+
+ igraph/src/dsyevr.c view
@@ -0,0 +1,759 @@+/*  -- 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;++/* > \brief <b> DSYEVR computes the eigenvalues and, optionally, the left and/or right eigenvectors for SY mat+rices</b>   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSYEVR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dsyevr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dsyevr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dsyevr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSYEVR( JOBZ, RANGE, UPLO, N, A, LDA, VL, VU, IL, IU,   +                            ABSTOL, M, W, Z, LDZ, ISUPPZ, WORK, LWORK,   +                            IWORK, LIWORK, INFO )   ++         CHARACTER          JOBZ, RANGE, UPLO   +         INTEGER            IL, INFO, IU, LDA, LDZ, LIWORK, LWORK, M, N   +         DOUBLE PRECISION   ABSTOL, VL, VU   +         INTEGER            ISUPPZ( * ), IWORK( * )   +         DOUBLE PRECISION   A( LDA, * ), W( * ), WORK( * ), Z( LDZ, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOBZ   +   > \verbatim   +   >          JOBZ is CHARACTER*1   +   >          = 'N':  Compute eigenvalues only;   +   >          = 'V':  Compute eigenvalues and eigenvectors.   +   > \endverbatim   +   >   +   > \param[in] RANGE   +   > \verbatim   +   >          RANGE is 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   +   > \endverbatim   +   >   +   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is CHARACTER*1   +   >          = 'U':  Upper triangle of A is stored;   +   >          = 'L':  Lower triangle of A is stored.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] VL   +   > \verbatim   +   >          VL is DOUBLE PRECISION   +   > \endverbatim   +   >   +   > \param[in] VU   +   > \verbatim   +   >          VU is 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'.   +   > \endverbatim   +   >   +   > \param[in] IL   +   > \verbatim   +   >          IL is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IU   +   > \verbatim   +   >          IU is 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'.   +   > \endverbatim   +   >   +   > \param[in] ABSTOL   +   > \verbatim   +   >          ABSTOL is 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.   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is INTEGER   +   >          The total number of eigenvalues found.  0 <= M <= N.   +   >          If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1.   +   > \endverbatim   +   >   +   > \param[out] W   +   > \verbatim   +   >          W is DOUBLE PRECISION array, dimension (N)   +   >          The first M elements contain the selected eigenvalues in   +   >          ascending order.   +   > \endverbatim   +   >   +   > \param[out] Z   +   > \verbatim   +   >          Z is 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.   +   > \endverbatim   +   >   +   > \param[in] LDZ   +   > \verbatim   +   >          LDZ is INTEGER   +   >          The leading dimension of the array Z.  LDZ >= 1, and if   +   >          JOBZ = 'V', LDZ >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] ISUPPZ   +   > \verbatim   +   >          ISUPPZ is 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   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (MAX(1,LIWORK))   +   >          On exit, if INFO = 0, IWORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LIWORK   +   > \verbatim   +   >          LIWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   >          > 0:  Internal error   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleSYeigen   ++   > \par Contributors:   +    ==================   +   >   +   >     Inderjit Dhillon, IBM Almaden, USA \n   +   >     Osni Marques, LBNL/NERSC, USA \n   +   >     Ken Stanley, Computer Science Division, University of   +   >       California at Berkeley, USA \n   +   >     Jason Riedy, Computer Science Division, University of   +   >       California at Berkeley, USA \n   +   >   +    =====================================================================   +   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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++   =====================================================================   +++       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 = indifl + *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_ */+
+ igraph/src/dsymv.c view
@@ -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_ */+
+ igraph/src/dsyr2.c view
@@ -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_ */+
+ igraph/src/dsyr2k.c view
@@ -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_ */+
+ igraph/src/dsyrk.c view
@@ -0,0 +1,361 @@+/*  -- 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 igraphdsyrk_(char *uplo, char *trans, integer *n, integer *k, +	doublereal *alpha, doublereal *a, integer *lda, doublereal *beta, +	doublereal *c__, integer *ldc)+{+    /* System generated locals */+    integer a_dim1, a_offset, c_dim1, c_offset, i__1, i__2, i__3;++    /* Local variables */+    integer i__, j, l, info;+    doublereal temp;+    extern logical igraphlsame_(char *, char *);+    integer nrowa;+    logical upper;+    extern /* Subroutine */ int igraphxerbla_(char *, integer *, ftnlen);+++/*  Purpose   +    =======   ++    DSYRK  performs one of the symmetric rank k operations   ++       C := alpha*A*A**T + beta*C,   ++    or   ++       C := alpha*A**T*A + beta*C,   ++    where  alpha and beta  are scalars, C is an  n by n  symmetric matrix   +    and  A  is an  n by k  matrix in the first case and a  k by n  matrix   +    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*A**T + beta*C.   ++                TRANS = 'T' or 't'   C := alpha*A**T*A + beta*C.   ++                TRANS = 'C' or 'c'   C := alpha*A**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   matrix   A,   and  on   entry   with   +             TRANS = 'T' or 't' or 'C' or 'c',  K  specifies  the  number   +             of rows of the matrix  A.  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.   ++    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;+    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 (*ldc < max(1,*n)) {+	info = 10;+    }+    if (info != 0) {+	igraphxerbla_("DSYRK ", &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*A**T + beta*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.) {+			temp = *alpha * a[j + l * a_dim1];+			i__3 = j;+			for (i__ = 1; i__ <= i__3; ++i__) {+			    c__[i__ + j * c_dim1] += temp * a[i__ + l * +				    a_dim1];+/* 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.) {+			temp = *alpha * a[j + l * a_dim1];+			i__3 = *n;+			for (i__ = j; i__ <= i__3; ++i__) {+			    c__[i__ + j * c_dim1] += temp * a[i__ + l * +				    a_dim1];+/* L160: */+			}+		    }+/* L170: */+		}+/* L180: */+	    }+	}+    } else {++/*        Form  C := alpha*A**T*A + beta*C. */++	if (upper) {+	    i__1 = *n;+	    for (j = 1; j <= i__1; ++j) {+		i__2 = j;+		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] * a[l + j * a_dim1];+/* L190: */+		    }+		    if (*beta == 0.) {+			c__[i__ + j * c_dim1] = *alpha * temp;+		    } else {+			c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[+				i__ + j * c_dim1];+		    }+/* L200: */+		}+/* L210: */+	    }+	} else {+	    i__1 = *n;+	    for (j = 1; j <= i__1; ++j) {+		i__2 = *n;+		for (i__ = j; i__ <= i__2; ++i__) {+		    temp = 0.;+		    i__3 = *k;+		    for (l = 1; l <= i__3; ++l) {+			temp += a[l + i__ * a_dim1] * a[l + j * a_dim1];+/* L220: */+		    }+		    if (*beta == 0.) {+			c__[i__ + j * c_dim1] = *alpha * temp;+		    } else {+			c__[i__ + j * c_dim1] = *alpha * temp + *beta * c__[+				i__ + j * c_dim1];+		    }+/* L230: */+		}+/* L240: */+	    }+	}+    }++    return 0;++/*     End of DSYRK . */++} /* igraphdsyrk_ */+
+ igraph/src/dsytd2.c view
@@ -0,0 +1,366 @@+/*  -- 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.;++/* > \brief \b DSYTD2 reduces a symmetric matrix to real symmetric tridiagonal form by an orthogonal similarit+y transformation (unblocked algorithm).   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSYTD2 + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dsytd2.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dsytd2.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dsytd2.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSYTD2( UPLO, N, A, LDA, D, E, TAU, INFO )   ++         CHARACTER          UPLO   +         INTEGER            INFO, LDA, N   +         DOUBLE PRECISION   A( LDA, * ), D( * ), E( * ), TAU( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DSYTD2 reduces a real symmetric matrix A to symmetric tridiagonal   +   > form T by an orthogonal similarity transformation: Q**T * A * Q = T.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is CHARACTER*1   +   >          Specifies whether the upper or lower triangular part of the   +   >          symmetric matrix A is stored:   +   >          = 'U':  Upper triangular   +   >          = 'L':  Lower triangular   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The diagonal elements of the tridiagonal matrix T:   +   >          D(i) = A(i,i).   +   > \endverbatim   +   >   +   > \param[out] E   +   > \verbatim   +   >          E is 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'.   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (N-1)   +   >          The scalar factors of the elementary reflectors (see Further   +   >          Details).   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup doubleSYcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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).   +   > \endverbatim   +   >   +    =====================================================================   +   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 computational routine (version 3.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dsytrd.c view
@@ -0,0 +1,428 @@+/*  -- 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.;++/* > \brief \b DSYTRD   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DSYTRD + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dsytrd.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dsytrd.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dsytrd.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DSYTRD( UPLO, N, A, LDA, D, E, TAU, WORK, LWORK, INFO )   ++         CHARACTER          UPLO   +         INTEGER            INFO, LDA, LWORK, N   +         DOUBLE PRECISION   A( LDA, * ), D( * ), E( * ), TAU( * ),   +        $                   WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > DSYTRD reduces a real symmetric matrix A to real symmetric   +   > tridiagonal form T by an orthogonal similarity transformation:   +   > Q**T * A * Q = T.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] UPLO   +   > \verbatim   +   >          UPLO is CHARACTER*1   +   >          = 'U':  Upper triangle of A is stored;   +   >          = 'L':  Lower triangle of A is stored.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix A.  N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] A   +   > \verbatim   +   >          A is 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.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A.  LDA >= max(1,N).   +   > \endverbatim   +   >   +   > \param[out] D   +   > \verbatim   +   >          D is DOUBLE PRECISION array, dimension (N)   +   >          The diagonal elements of the tridiagonal matrix T:   +   >          D(i) = A(i,i).   +   > \endverbatim   +   >   +   > \param[out] E   +   > \verbatim   +   >          E is 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'.   +   > \endverbatim   +   >   +   > \param[out] TAU   +   > \verbatim   +   >          TAU is DOUBLE PRECISION array, dimension (N-1)   +   >          The scalar factors of the elementary reflectors (see Further   +   >          Details).   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleSYcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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).   +   > \endverbatim   +   >   +    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dtime_.c view
@@ -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
+ igraph/src/dtrevc.c view
@@ -0,0 +1,1306 @@+/*  -- 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_;++/* > \brief \b DTREVC   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DTREVC + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dtrevc.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dtrevc.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dtrevc.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DTREVC( SIDE, HOWMNY, SELECT, N, T, LDT, VL, LDVL, VR,   +                            LDVR, MM, M, WORK, INFO )   ++         CHARACTER          HOWMNY, SIDE   +         INTEGER            INFO, LDT, LDVL, LDVR, M, MM, N   +         LOGICAL            SELECT( * )   +         DOUBLE PRECISION   T( LDT, * ), VL( LDVL, * ), VR( LDVR, * ),   +        $                   WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SIDE   +   > \verbatim   +   >          SIDE is CHARACTER*1   +   >          = 'R':  compute right eigenvectors only;   +   >          = 'L':  compute left eigenvectors only;   +   >          = 'B':  compute both right and left eigenvectors.   +   > \endverbatim   +   >   +   > \param[in] HOWMNY   +   > \verbatim   +   >          HOWMNY is 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.   +   > \endverbatim   +   >   +   > \param[in,out] SELECT   +   > \verbatim   +   >          SELECT is 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'.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix T. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] T   +   > \verbatim   +   >          T is DOUBLE PRECISION array, dimension (LDT,N)   +   >          The upper quasi-triangular matrix T in Schur canonical form.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the array T. LDT >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in,out] VL   +   > \verbatim   +   >          VL is 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'.   +   > \endverbatim   +   >   +   > \param[in] LDVL   +   > \verbatim   +   >          LDVL is INTEGER   +   >          The leading dimension of the array VL.  LDVL >= 1, and if   +   >          SIDE = 'L' or 'B', LDVL >= N.   +   > \endverbatim   +   >   +   > \param[in,out] VR   +   > \verbatim   +   >          VR is 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'.   +   > \endverbatim   +   >   +   > \param[in] LDVR   +   > \verbatim   +   >          LDVR is INTEGER   +   >          The leading dimension of the array VR.  LDVR >= 1, and if   +   >          SIDE = 'R' or 'B', LDVR >= N.   +   > \endverbatim   +   >   +   > \param[in] MM   +   > \verbatim   +   >          MM is INTEGER   +   >          The number of columns in the arrays VL and/or VR. MM >= M.   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (3*N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0:  successful exit   +   >          < 0:  if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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|.   +   > \endverbatim   +   >   +    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dtrexc.c view
@@ -0,0 +1,468 @@+/*  -- 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;++/* > \brief \b DTREXC   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DTREXC + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dtrexc.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dtrexc.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dtrexc.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DTREXC( COMPQ, N, T, LDT, Q, LDQ, IFST, ILST, WORK,   +                            INFO )   ++         CHARACTER          COMPQ   +         INTEGER            IFST, ILST, INFO, LDQ, LDT, N   +         DOUBLE PRECISION   Q( LDQ, * ), T( LDT, * ), WORK( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] COMPQ   +   > \verbatim   +   >          COMPQ is CHARACTER*1   +   >          = 'V':  update the matrix Q of Schur vectors;   +   >          = 'N':  do not update Q.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix T. N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] T   +   > \verbatim   +   >          T is 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.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the array T. LDT >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in,out] Q   +   > \verbatim   +   >          Q is 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.   +   > \endverbatim   +   >   +   > \param[in] LDQ   +   > \verbatim   +   >          LDQ is INTEGER   +   >          The leading dimension of the array Q.  LDQ >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in,out] IFST   +   > \verbatim   +   >          IFST is INTEGER   +   > \endverbatim   +   >   +   > \param[in,out] ILST   +   > \verbatim   +   >          ILST is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dtrmm.c view
@@ -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_ */+
+ igraph/src/dtrmv.c view
@@ -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_ */+
+ igraph/src/dtrsen.c view
@@ -0,0 +1,623 @@+/*  -- 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;++/* > \brief \b DTRSEN   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DTRSEN + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dtrsen.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dtrsen.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dtrsen.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DTRSEN( JOB, COMPQ, SELECT, N, T, LDT, Q, LDQ, WR, WI,   +                            M, S, SEP, WORK, LWORK, IWORK, LIWORK, INFO )   ++         CHARACTER          COMPQ, JOB   +         INTEGER            INFO, LDQ, LDT, LIWORK, LWORK, M, N   +         DOUBLE PRECISION   S, SEP   +         LOGICAL            SELECT( * )   +         INTEGER            IWORK( * )   +         DOUBLE PRECISION   Q( LDQ, * ), T( LDT, * ), WI( * ), WORK( * ),   +        $                   WR( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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 elements equal and its   +   > off-diagonal elements of opposite sign.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOB   +   > \verbatim   +   >          JOB is 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).   +   > \endverbatim   +   >   +   > \param[in] COMPQ   +   > \verbatim   +   >          COMPQ is CHARACTER*1   +   >          = 'V': update the matrix Q of Schur vectors;   +   >          = 'N': do not update Q.   +   > \endverbatim   +   >   +   > \param[in] SELECT   +   > \verbatim   +   >          SELECT is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix T. N >= 0.   +   > \endverbatim   +   >   +   > \param[in,out] T   +   > \verbatim   +   >          T is 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.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the array T. LDT >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in,out] Q   +   > \verbatim   +   >          Q is 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.   +   > \endverbatim   +   >   +   > \param[in] LDQ   +   > \verbatim   +   >          LDQ is INTEGER   +   >          The leading dimension of the array Q.   +   >          LDQ >= 1; and if COMPQ = 'V', LDQ >= N.   +   > \endverbatim   +   >   +   > \param[out] WR   +   > \verbatim   +   >          WR is DOUBLE PRECISION array, dimension (N)   +   > \endverbatim   +   > \param[out] WI   +   > \verbatim   +   >          WI is 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.   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is INTEGER   +   >          The dimension of the specified invariant subspace.   +   >          0 < = M <= N.   +   > \endverbatim   +   >   +   > \param[out] S   +   > \verbatim   +   >          S is 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.   +   > \endverbatim   +   >   +   > \param[out] SEP   +   > \verbatim   +   >          SEP is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (MAX(1,LWORK))   +   >          On exit, if INFO = 0, WORK(1) returns the optimal LWORK.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (MAX(1,LIWORK))   +   >          On exit, if INFO = 0, IWORK(1) returns the optimal LIWORK.   +   > \endverbatim   +   >   +   > \param[in] LIWORK   +   > \verbatim   +   >          LIWORK is 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.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date April 2012   ++   > \ingroup doubleOTHERcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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   +   > \endverbatim   +   >   +    =====================================================================   +   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 = 0;+    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 computational routine (version 3.4.1) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       April 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/dtrsm.c view
@@ -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_ */+
+ igraph/src/dtrsna.c view
@@ -0,0 +1,696 @@+/*  -- 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_;++/* > \brief \b DTRSNA   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DTRSNA + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dtrsna.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dtrsna.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dtrsna.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DTRSNA( JOB, HOWMNY, SELECT, N, T, LDT, VL, LDVL, VR,   +                            LDVR, S, SEP, MM, M, WORK, LDWORK, IWORK,   +                            INFO )   ++         CHARACTER          HOWMNY, JOB   +         INTEGER            INFO, LDT, LDVL, LDVR, LDWORK, M, MM, N   +         LOGICAL            SELECT( * )   +         INTEGER            IWORK( * )   +         DOUBLE PRECISION   S( * ), SEP( * ), T( LDT, * ), VL( LDVL, * ),   +        $                   VR( LDVR, * ), WORK( LDWORK, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] JOB   +   > \verbatim   +   >          JOB is 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).   +   > \endverbatim   +   >   +   > \param[in] HOWMNY   +   > \verbatim   +   >          HOWMNY is CHARACTER*1   +   >          = 'A': compute condition numbers for all eigenpairs;   +   >          = 'S': compute condition numbers for selected eigenpairs   +   >                 specified by the array SELECT.   +   > \endverbatim   +   >   +   > \param[in] SELECT   +   > \verbatim   +   >          SELECT is 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.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix T. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] T   +   > \verbatim   +   >          T is DOUBLE PRECISION array, dimension (LDT,N)   +   >          The upper quasi-triangular matrix T, in Schur canonical form.   +   > \endverbatim   +   >   +   > \param[in] LDT   +   > \verbatim   +   >          LDT is INTEGER   +   >          The leading dimension of the array T. LDT >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in] VL   +   > \verbatim   +   >          VL is 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.   +   > \endverbatim   +   >   +   > \param[in] LDVL   +   > \verbatim   +   >          LDVL is INTEGER   +   >          The leading dimension of the array VL.   +   >          LDVL >= 1; and if JOB = 'E' or 'B', LDVL >= N.   +   > \endverbatim   +   >   +   > \param[in] VR   +   > \verbatim   +   >          VR is 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.   +   > \endverbatim   +   >   +   > \param[in] LDVR   +   > \verbatim   +   >          LDVR is INTEGER   +   >          The leading dimension of the array VR.   +   >          LDVR >= 1; and if JOB = 'E' or 'B', LDVR >= N.   +   > \endverbatim   +   >   +   > \param[out] S   +   > \verbatim   +   >          S is 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.   +   > \endverbatim   +   >   +   > \param[out] SEP   +   > \verbatim   +   >          SEP is 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.   +   > \endverbatim   +   >   +   > \param[in] MM   +   > \verbatim   +   >          MM is INTEGER   +   >          The number of elements in the arrays S (if JOB = 'E' or 'B')   +   >           and/or SEP (if JOB = 'V' or 'B'). MM >= M.   +   > \endverbatim   +   >   +   > \param[out] M   +   > \verbatim   +   >          M is 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.   +   > \endverbatim   +   >   +   > \param[out] WORK   +   > \verbatim   +   >          WORK is DOUBLE PRECISION array, dimension (LDWORK,N+6)   +   >          If JOB = 'E', WORK is not referenced.   +   > \endverbatim   +   >   +   > \param[in] LDWORK   +   > \verbatim   +   >          LDWORK is INTEGER   +   >          The leading dimension of the array WORK.   +   >          LDWORK >= 1; and if JOB = 'V' or 'B', LDWORK >= N.   +   > \endverbatim   +   >   +   > \param[out] IWORK   +   > \verbatim   +   >          IWORK is INTEGER array, dimension (2*(N-1))   +   >          If JOB = 'E', IWORK is not referenced.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          = 0: successful exit   +   >          < 0: if INFO = -i, the i-th argument had an illegal value   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleOTHERcomputational   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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)   +   > \endverbatim   +   >   +    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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_ */+
+ igraph/src/dtrsv.c view
@@ -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 igraphdtrsv_(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   +    =======   ++    DTRSV  solves one of the systems of equations   ++       A*x = b,   or   A**T*x = b,   ++    where b and x are n element vectors and A is an n by n unit, or   +    non-unit, upper or lower triangular matrix.   ++    No test for singularity or near-singularity is included in this   +    routine. Such tests must be performed before calling this routine.   ++    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 equations to be solved as   +             follows:   ++                TRANS = 'N' or 'n'   A*x = b.   ++                TRANS = 'T' or 't'   A**T*x = b.   ++                TRANS = 'C' or 'c'   A**T*x = b.   ++             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 right-hand side vector b. On exit, X is overwritten   +             with the solution vector x.   ++    INCX   - INTEGER.   +             On entry, INCX specifies the increment for the elements of   +             X. INCX must not be zero.   +             Unchanged on exit.   +++    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 */+    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_("DTRSV ", &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 := inv( A )*x. */++	if (igraphlsame_(uplo, "U")) {+	    if (*incx == 1) {+		for (j = *n; j >= 1; --j) {+		    if (x[j] != 0.) {+			if (nounit) {+			    x[j] /= a[j + j * a_dim1];+			}+			temp = x[j];+			for (i__ = j - 1; i__ >= 1; --i__) {+			    x[i__] -= temp * a[i__ + j * a_dim1];+/* L10: */+			}+		    }+/* L20: */+		}+	    } else {+		jx = kx + (*n - 1) * *incx;+		for (j = *n; j >= 1; --j) {+		    if (x[jx] != 0.) {+			if (nounit) {+			    x[jx] /= a[j + j * a_dim1];+			}+			temp = x[jx];+			ix = jx;+			for (i__ = j - 1; i__ >= 1; --i__) {+			    ix -= *incx;+			    x[ix] -= temp * a[i__ + j * a_dim1];+/* L30: */+			}+		    }+		    jx -= *incx;+/* L40: */+		}+	    }+	} else {+	    if (*incx == 1) {+		i__1 = *n;+		for (j = 1; j <= i__1; ++j) {+		    if (x[j] != 0.) {+			if (nounit) {+			    x[j] /= a[j + j * a_dim1];+			}+			temp = x[j];+			i__2 = *n;+			for (i__ = j + 1; i__ <= i__2; ++i__) {+			    x[i__] -= temp * a[i__ + j * a_dim1];+/* L50: */+			}+		    }+/* L60: */+		}+	    } else {+		jx = kx;+		i__1 = *n;+		for (j = 1; j <= i__1; ++j) {+		    if (x[jx] != 0.) {+			if (nounit) {+			    x[jx] /= a[j + j * a_dim1];+			}+			temp = x[jx];+			ix = jx;+			i__2 = *n;+			for (i__ = j + 1; i__ <= i__2; ++i__) {+			    ix += *incx;+			    x[ix] -= temp * a[i__ + j * a_dim1];+/* L70: */+			}+		    }+		    jx += *incx;+/* L80: */+		}+	    }+	}+    } else {++/*        Form  x := inv( A**T )*x. */++	if (igraphlsame_(uplo, "U")) {+	    if (*incx == 1) {+		i__1 = *n;+		for (j = 1; j <= i__1; ++j) {+		    temp = x[j];+		    i__2 = j - 1;+		    for (i__ = 1; i__ <= i__2; ++i__) {+			temp -= a[i__ + j * a_dim1] * x[i__];+/* L90: */+		    }+		    if (nounit) {+			temp /= a[j + j * a_dim1];+		    }+		    x[j] = temp;+/* L100: */+		}+	    } else {+		jx = kx;+		i__1 = *n;+		for (j = 1; j <= i__1; ++j) {+		    temp = x[jx];+		    ix = kx;+		    i__2 = j - 1;+		    for (i__ = 1; i__ <= i__2; ++i__) {+			temp -= a[i__ + j * a_dim1] * x[ix];+			ix += *incx;+/* L110: */+		    }+		    if (nounit) {+			temp /= a[j + j * a_dim1];+		    }+		    x[jx] = temp;+		    jx += *incx;+/* L120: */+		}+	    }+	} else {+	    if (*incx == 1) {+		for (j = *n; j >= 1; --j) {+		    temp = x[j];+		    i__1 = j + 1;+		    for (i__ = *n; i__ >= i__1; --i__) {+			temp -= a[i__ + j * a_dim1] * x[i__];+/* L130: */+		    }+		    if (nounit) {+			temp /= a[j + j * a_dim1];+		    }+		    x[j] = temp;+/* L140: */+		}+	    } else {+		kx += (*n - 1) * *incx;+		jx = kx;+		for (j = *n; j >= 1; --j) {+		    temp = x[jx];+		    ix = kx;+		    i__1 = j + 1;+		    for (i__ = *n; i__ >= i__1; --i__) {+			temp -= a[i__ + j * a_dim1] * x[ix];+			ix -= *incx;+/* L150: */+		    }+		    if (nounit) {+			temp /= a[j + j * a_dim1];+		    }+		    x[jx] = temp;+		    jx -= *incx;+/* L160: */+		}+	    }+	}+    }++    return 0;++/*     End of DTRSV . */++} /* igraphdtrsv_ */+
+ igraph/src/dtrsyl.c view
@@ -0,0 +1,1389 @@+/*  -- 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_;++/* > \brief \b DTRSYL   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download DTRSYL + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/dtrsyl.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/dtrsyl.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/dtrsyl.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE DTRSYL( TRANA, TRANB, ISGN, M, N, A, LDA, B, LDB, C,   +                            LDC, SCALE, INFO )   ++         CHARACTER          TRANA, TRANB   +         INTEGER            INFO, ISGN, LDA, LDB, LDC, M, N   +         DOUBLE PRECISION   SCALE   +         DOUBLE PRECISION   A( LDA, * ), B( LDB, * ), C( LDC, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] TRANA   +   > \verbatim   +   >          TRANA is 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)   +   > \endverbatim   +   >   +   > \param[in] TRANB   +   > \verbatim   +   >          TRANB is 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)   +   > \endverbatim   +   >   +   > \param[in] ISGN   +   > \verbatim   +   >          ISGN is 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   +   > \endverbatim   +   >   +   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The order of the matrix A, and the number of rows in the   +   >          matrices X and C. M >= 0.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The order of the matrix B, and the number of columns in the   +   >          matrices X and C. N >= 0.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,M)   +   >          The upper quasi-triangular matrix A, in Schur canonical form.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A. LDA >= max(1,M).   +   > \endverbatim   +   >   +   > \param[in] B   +   > \verbatim   +   >          B is DOUBLE PRECISION array, dimension (LDB,N)   +   >          The upper quasi-triangular matrix B, in Schur canonical form.   +   > \endverbatim   +   >   +   > \param[in] LDB   +   > \verbatim   +   >          LDB is INTEGER   +   >          The leading dimension of the array B. LDB >= max(1,N).   +   > \endverbatim   +   >   +   > \param[in,out] C   +   > \verbatim   +   >          C is 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.   +   > \endverbatim   +   >   +   > \param[in] LDC   +   > \verbatim   +   >          LDC is INTEGER   +   >          The leading dimension of the array C. LDC >= max(1,M)   +   > \endverbatim   +   >   +   > \param[out] SCALE   +   > \verbatim   +   >          SCALE is DOUBLE PRECISION   +   >          The scale factor, scale, set <= 1 to avoid overflow in X.   +   > \endverbatim   +   >   +   > \param[out] INFO   +   > \verbatim   +   >          INFO is 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).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup doubleSYcomputational   ++    =====================================================================   +   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 computational routine (version 3.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    =====================================================================   +++       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        T                    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_ */+
+ igraph/src/due.c view
@@ -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
+ igraph/src/dummy.c view
@@ -0,0 +1,2 @@++int MAIN__(void) { return 0; }
+ igraph/src/dvout.c view
@@ -0,0 +1,276 @@+/*  -- 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_ */+
+ igraph/src/ef1asc_.c view
@@ -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
+ igraph/src/ef1cmc_.c view
@@ -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
+ igraph/src/eigen.c view
@@ -0,0 +1,1520 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/embedding.c view
@@ -0,0 +1,1170 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_embedding.h"+#include "igraph_interface.h"+#include "igraph_adjlist.h"+#include "igraph_random.h"+#include "igraph_centrality.h"+#include "igraph_blas.h"++typedef struct {+    const igraph_t *graph;+    const igraph_vector_t *cvec;+    const igraph_vector_t *cvec2;+    igraph_adjlist_t *outlist, *inlist;+    igraph_inclist_t *eoutlist, *einlist;+    igraph_vector_t *tmp;+    const igraph_vector_t *weights;+} igraph_i_asembedding_data_t;++/* Adjacency matrix, unweighted, undirected.+   Eigendecomposition is used */+int igraph_i_asembeddingu(igraph_real_t *to, const igraph_real_t *from,+                          int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_adjlist_t *outlist = data->outlist;+    const igraph_vector_t *cvec = data->cvec;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* to = (A+cD) from */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(outlist, i);+        nlen = igraph_vector_int_size(neis);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int nei = (long int) VECTOR(*neis)[j];+            to[i] += from[nei];+        }+        to[i] += VECTOR(*cvec)[i] * from[i];+    }++    return 0;+}++/* Adjacency matrix, weighted, undirected.+   Eigendecomposition is used. */+int igraph_i_asembeddinguw(igraph_real_t *to, const igraph_real_t *from,+                           int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_inclist_t *outlist = data->eoutlist;+    const igraph_vector_t *cvec = data->cvec;+    const igraph_vector_t *weights = data->weights;+    const igraph_t *graph = data->graph;+    igraph_vector_int_t *incs;+    int i, j, nlen;++    /* to = (A+cD) from */+    for (i = 0; i < n; i++) {+        incs = igraph_inclist_get(outlist, i);+        nlen = igraph_vector_int_size(incs);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*incs)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            to[i] += w * from[nei];+        }+        to[i] += VECTOR(*cvec)[i] * from[i];+    }++    return 0;+}++/* Adjacency matrix, unweighted, directed. SVD. */+int igraph_i_asembedding(igraph_real_t *to, const igraph_real_t *from,+                         int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_adjlist_t *outlist = data->outlist;+    igraph_adjlist_t *inlist = data->inlist;+    const igraph_vector_t *cvec = data->cvec;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* tmp = (A+cD)' from */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(inlist, i);+        nlen = igraph_vector_int_size(neis);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int nei = (long int) VECTOR(*neis)[j];+            VECTOR(*tmp)[i] += from[nei];+        }+        VECTOR(*tmp)[i] += VECTOR(*cvec)[i] * from[i];+    }++    /* to = (A+cD) tmp */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(outlist, i);+        nlen = igraph_vector_int_size(neis);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int nei = (long int) VECTOR(*neis)[j];+            to[i] += VECTOR(*tmp)[nei];+        }+        to[i] += VECTOR(*cvec)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++/* Adjacency matrix, unweighted, directed. SVD, right eigenvectors */+int igraph_i_asembedding_right(igraph_real_t *to, const igraph_real_t *from,+                               int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_adjlist_t *inlist = data->inlist;+    const igraph_vector_t *cvec = data->cvec;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* to = (A+cD)' from */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(inlist, i);+        nlen = igraph_vector_int_size(neis);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int nei = (long int) VECTOR(*neis)[j];+            to[i] += from[nei];+        }+        to[i] += VECTOR(*cvec)[i] * from[i];+    }++    return 0;+}++/* Adjacency matrix, weighted, directed. SVD. */+int igraph_i_asembeddingw(igraph_real_t *to, const igraph_real_t *from,+                          int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_inclist_t *outlist = data->eoutlist;+    igraph_inclist_t *inlist = data->einlist;+    const igraph_vector_t *cvec = data->cvec;+    const igraph_vector_t *weights = data->weights;+    const igraph_t *graph = data->graph;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *incs;+    int i, j, nlen;++    /* tmp = (A+cD)' from */+    for (i = 0; i < n; i++) {+        incs = igraph_inclist_get(inlist, i);+        nlen = igraph_vector_int_size(incs);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*incs)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            VECTOR(*tmp)[i] += w * from[nei];+        }+        VECTOR(*tmp)[i] += VECTOR(*cvec)[i] * from[i];+    }++    /* to = (A+cD) tmp */+    for (i = 0; i < n; i++) {+        incs = igraph_inclist_get(outlist, i);+        nlen = igraph_vector_int_size(incs);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*incs)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            to[i] += w * VECTOR(*tmp)[nei];+        }+        to[i] += VECTOR(*cvec)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++/* Adjacency matrix, weighted, directed. SVD, right eigenvectors. */+int igraph_i_asembeddingw_right(igraph_real_t *to, const igraph_real_t *from,+                                int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_inclist_t *inlist = data->einlist;+    const igraph_vector_t *cvec = data->cvec;+    const igraph_vector_t *weights = data->weights;+    const igraph_t *graph = data->graph;+    igraph_vector_int_t *incs;+    int i, j, nlen;++    /* to = (A+cD)' from */+    for (i = 0; i < n; i++) {+        incs = igraph_inclist_get(inlist, i);+        nlen = igraph_vector_int_size(incs);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*incs)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            to[i] += w * from[nei];+        }+        to[i] += VECTOR(*cvec)[i] * from[i];+    }++    return 0;+}++/* Laplacian D-A, unweighted, undirected. Eigendecomposition. */+int igraph_i_lsembedding_da(igraph_real_t *to, const igraph_real_t *from,+                            int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_adjlist_t *outlist = data->outlist;+    const igraph_vector_t *cvec = data->cvec;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* to = (D-A) from */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(outlist, i);+        nlen = igraph_vector_int_size(neis);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int nei = (long int) VECTOR(*neis)[j];+            to[i] -= from[nei];+        }+        to[i] += VECTOR(*cvec)[i] * from[i];+    }++    return 0;+}++/* Laplacian D-A, weighted, undirected. Eigendecomposition. */+int igraph_i_lsembedding_daw(igraph_real_t *to, const igraph_real_t *from,+                             int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_inclist_t *outlist = data->eoutlist;+    const igraph_vector_t *cvec = data->cvec;+    const igraph_vector_t *weights = data->weights;+    const igraph_t *graph = data->graph;+    igraph_vector_int_t *incs;+    int i, j, nlen;++    /* to = (D-A) from */+    for (i = 0; i < n; i++) {+        incs = igraph_inclist_get(outlist, i);+        nlen = igraph_vector_int_size(incs);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*incs)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            to[i] -= w * from[nei];+        }+        to[i] += VECTOR(*cvec)[i] * from[i];+    }++    return 0;+}++/* Laplacian DAD, unweighted, undirected. Eigendecomposition. */+int igraph_i_lsembedding_dad(igraph_real_t *to, const igraph_real_t *from,+                             int n, void *extra) {++    igraph_i_asembedding_data_t *data = extra;+    igraph_adjlist_t *outlist = data->outlist;+    const igraph_vector_t *cvec = data->cvec;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* to = D^1/2 from */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*cvec)[i] * from[i];+    }++    /* tmp = A to */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(outlist, i);+        nlen = igraph_vector_int_size(neis);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int nei = (long int) VECTOR(*neis)[j];+            VECTOR(*tmp)[i] += to[nei];+        }+    }++    /* to = D tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*cvec)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++int igraph_i_lsembedding_dadw(igraph_real_t *to, const igraph_real_t *from,+                              int n, void *extra) {++    igraph_i_asembedding_data_t *data = extra;+    igraph_inclist_t *outlist = data->eoutlist;+    const igraph_vector_t *cvec = data->cvec;+    const igraph_vector_t *weights = data->weights;+    const igraph_t *graph = data->graph;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *incs;+    int i, j, nlen;++    /* to = D^-1/2 from */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*cvec)[i] * from[i];+    }++    /* tmp = A' to */+    for (i = 0; i < n; i++) {+        incs = igraph_inclist_get(outlist, i);+        nlen = igraph_vector_int_size(incs);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*incs)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            VECTOR(*tmp)[i] += w * to[nei];+        }+    }++    /* to = D tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*cvec)[i] * VECTOR(*cvec)[i] * VECTOR(*tmp)[i];+    }++    /* tmp = A to */+    for (i = 0; i < n; i++) {+        incs = igraph_inclist_get(outlist, i);+        nlen = igraph_vector_int_size(incs);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            long int edge = VECTOR(*incs)[j];+            long int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            VECTOR(*tmp)[i] += w * to[nei];+        }+    }++    /* to = D^-1/2 tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*cvec)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++/* Laplacian I-DAD, unweighted, undirected. Eigendecomposition. */+int igraph_i_lsembedding_idad(igraph_real_t *to, const igraph_real_t *from,+                              int n, void *extra) {++    int i;++    igraph_i_lsembedding_dad(to, from, n, extra);+    for (i = 0; i < n; i++) {+        to[i] = from[i] - to[i];+    }++    return 0;+}++int igraph_i_lsembedding_idadw(igraph_real_t *to, const igraph_real_t *from,+                               int n, void *extra) {+    int i;++    igraph_i_lsembedding_dadw(to, from, n, extra);+    for (i = 0; i < n; i++) {+        to[i] = from[i] - to[i];+    }++    return 0;+}++/* Laplacian OAP, unweighted, directed. SVD. */+int igraph_i_lseembedding_oap(igraph_real_t *to, const igraph_real_t *from,+                              int n, void *extra) {++    igraph_i_asembedding_data_t *data = extra;+    igraph_adjlist_t *outlist = data->outlist;+    igraph_adjlist_t *inlist = data->inlist;+    const igraph_vector_t *deg_in = data->cvec;+    const igraph_vector_t *deg_out = data->cvec2;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* tmp = O' from */+    for (i = 0; i < n; i++) {+        VECTOR(*tmp)[i] = VECTOR(*deg_out)[i] * from[i];+    }++    /* to = A' tmp */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(inlist, i);+        nlen = igraph_vector_int_size(neis);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            int nei = VECTOR(*neis)[j];+            to[i] += VECTOR(*tmp)[nei];+        }+    }++    /* tmp = P' to */+    for (i = 0; i < n; i++) {+        VECTOR(*tmp)[i] = VECTOR(*deg_in)[i] * to[i];+    }++    /* to = P tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i];+    }++    /* tmp = A to */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(outlist, i);+        nlen = igraph_vector_int_size(neis);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            int nei = VECTOR(*neis)[j];+            VECTOR(*tmp)[i] += to[nei];+        }+    }++    /* to = O tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_out)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++/* Laplacian OAP, unweighted, directed. SVD, right eigenvectors. */+int igraph_i_lseembedding_oap_right(igraph_real_t *to,+                                    const igraph_real_t *from,+                                    int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_adjlist_t *inlist = data->inlist;+    const igraph_vector_t *deg_in = data->cvec;+    const igraph_vector_t *deg_out = data->cvec2;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* to = O' from */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_out)[i] * from[i];+    }++    /* tmp = A' to */+    for (i = 0; i < n; i++) {+        neis = igraph_adjlist_get(inlist, i);+        nlen = igraph_vector_int_size(neis);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            int nei = VECTOR(*neis)[j];+            VECTOR(*tmp)[i] += to[nei];+        }+    }++    /* to = P' tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++/* Laplacian OAP, weighted, directed. SVD. */+int igraph_i_lseembedding_oapw(igraph_real_t *to, const igraph_real_t *from,+                               int n, void *extra) {++    igraph_i_asembedding_data_t *data = extra;+    igraph_inclist_t *outlist = data->eoutlist;+    igraph_inclist_t *inlist = data->einlist;+    const igraph_vector_t *deg_in = data->cvec;+    const igraph_vector_t *deg_out = data->cvec2;+    const igraph_vector_t *weights = data->weights;+    const igraph_t *graph = data->graph;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* tmp = O' from */+    for (i = 0; i < n; i++) {+        VECTOR(*tmp)[i] = VECTOR(*deg_out)[i] * from[i];+    }++    /* to = A' tmp */+    for (i = 0; i < n; i++) {+        neis = igraph_inclist_get(inlist, i);+        nlen = igraph_vector_int_size(neis);+        to[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            int edge = VECTOR(*neis)[j];+            int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            to[i] += w * VECTOR(*tmp)[nei];+        }+    }++    /* tmp = P' to */+    for (i = 0; i < n; i++) {+        VECTOR(*tmp)[i] = VECTOR(*deg_in)[i] * to[i];+    }++    /* to = P tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i];+    }++    /* tmp = A to */+    for (i = 0; i < n; i++) {+        neis = igraph_inclist_get(outlist, i);+        nlen = igraph_vector_int_size(neis);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            int edge = VECTOR(*neis)[j];+            int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            VECTOR(*tmp)[i] += w * to[nei];+        }+    }++    /* to = O tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_out)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++/* Laplacian OAP, weighted, directed. SVD, right eigenvectors. */+int igraph_i_lseembedding_oapw_right(igraph_real_t *to,+                                     const igraph_real_t *from,+                                     int n, void *extra) {+    igraph_i_asembedding_data_t *data = extra;+    igraph_inclist_t *inlist = data->einlist;+    const igraph_vector_t *deg_in = data->cvec;+    const igraph_vector_t *deg_out = data->cvec2;+    const igraph_vector_t *weights = data->weights;+    const igraph_t *graph = data->graph;+    igraph_vector_t *tmp = data->tmp;+    igraph_vector_int_t *neis;+    int i, j, nlen;++    /* to = O' from */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_out)[i] * from[i];+    }++    /* tmp = A' to */+    for (i = 0; i < n; i++) {+        neis = igraph_inclist_get(inlist, i);+        nlen = igraph_vector_int_size(neis);+        VECTOR(*tmp)[i] = 0.0;+        for (j = 0; j < nlen; j++) {+            int edge = VECTOR(*neis)[j];+            int nei = IGRAPH_OTHER(graph, edge, i);+            igraph_real_t w = VECTOR(*weights)[edge];+            VECTOR(*tmp)[i] += w * to[nei];+        }+    }++    /* to = P' tmp */+    for (i = 0; i < n; i++) {+        to[i] = VECTOR(*deg_in)[i] * VECTOR(*tmp)[i];+    }++    return 0;+}++int igraph_i_spectral_embedding(const igraph_t *graph,+                                igraph_integer_t no,+                                const igraph_vector_t *weights,+                                igraph_eigen_which_position_t which,+                                igraph_bool_t scaled,+                                igraph_matrix_t *X,+                                igraph_matrix_t *Y,+                                igraph_vector_t *D,+                                const igraph_vector_t *cvec,+                                const igraph_vector_t *cvec2,+                                igraph_arpack_options_t *options,+                                igraph_arpack_function_t *callback,+                                igraph_arpack_function_t *callback_right,+                                igraph_bool_t symmetric,+                                igraph_bool_t eigen,+                                igraph_bool_t zapsmall) {++    igraph_integer_t vc = igraph_vcount(graph);+    igraph_vector_t tmp;+    igraph_adjlist_t outlist, inlist;+    igraph_inclist_t eoutlist, einlist;+    int i, j, cveclen = igraph_vector_size(cvec);+    igraph_i_asembedding_data_t data = { graph, cvec, cvec2, &outlist, &inlist,+                                         &eoutlist, &einlist, &tmp, weights+                                       };+    igraph_vector_t tmpD;++    if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {+        IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+    }++    if (which != IGRAPH_EIGEN_LM &&+        which != IGRAPH_EIGEN_LA &&+        which != IGRAPH_EIGEN_SA) {+        IGRAPH_ERROR("Invalid eigenvalue chosen, must be one of "+                     "`largest magnitude', `largest algebraic' or "+                     "`smallest algebraic'", IGRAPH_EINVAL);+    }++    if (no > vc) {+        IGRAPH_ERROR("Too many singular values requested", IGRAPH_EINVAL);+    }+    if (no <= 0) {+        IGRAPH_ERROR("No singular values requested", IGRAPH_EINVAL);+    }++    if (cveclen != 1 && cveclen != vc) {+        IGRAPH_ERROR("Augmentation vector size is invalid, it should be "+                     "the number of vertices or scalar", IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_matrix_resize(X, vc, no));+    if (Y) {+        IGRAPH_CHECK(igraph_matrix_resize(Y, vc, no));+    }++    /* empty graph */+    if (igraph_ecount(graph) == 0) {+        igraph_matrix_null(X);+        if (Y) {+            igraph_matrix_null(Y);+        }+        return 0;+    }++    igraph_vector_init(&tmp, vc);+    IGRAPH_FINALLY(igraph_vector_destroy, &tmp);+    if (!weights) {+        IGRAPH_CHECK(igraph_adjlist_init(graph, &outlist, IGRAPH_OUT));+        IGRAPH_FINALLY(igraph_adjlist_destroy, &outlist);+        if (!symmetric) {+            IGRAPH_CHECK(igraph_adjlist_init(graph, &inlist, IGRAPH_IN));+            IGRAPH_FINALLY(igraph_adjlist_destroy, &inlist);+        }+    } else {+        IGRAPH_CHECK(igraph_inclist_init(graph, &eoutlist, IGRAPH_OUT));+        IGRAPH_FINALLY(igraph_inclist_destroy, &eoutlist);+        if (!symmetric) {+            IGRAPH_CHECK(igraph_inclist_init(graph, &einlist, IGRAPH_IN));+            IGRAPH_FINALLY(igraph_inclist_destroy, &einlist);+        }+    }+    IGRAPH_VECTOR_INIT_FINALLY(&tmpD, no);++    options->n = vc;+    options->start = 0;   /* random start vector */+    options->nev = no;+    switch (which) {+    case IGRAPH_EIGEN_LM:+        options->which[0] = 'L'; options->which[1] = 'M';+        break;+    case IGRAPH_EIGEN_LA:+        options->which[0] = 'L'; options->which[1] = 'A';+        break;+    case IGRAPH_EIGEN_SA:+        options->which[0] = 'S'; options->which[1] = 'A';+        break;+    default:+        break;+    }+    options->ncv = no + 3;+    if (options->ncv > vc) {+        options->ncv = vc;+    }++    IGRAPH_CHECK(igraph_arpack_rssolve(callback, &data, options, 0, &tmpD, X));++    if (!symmetric) {+        /* calculate left eigenvalues */+        IGRAPH_CHECK(igraph_matrix_resize(Y, vc, no));+        for (i = 0; i < no; i++) {+            igraph_real_t norm;+            igraph_vector_t v;+            callback_right(&MATRIX(*Y, 0, i), &MATRIX(*X, 0, i), vc, &data);+            igraph_vector_view(&v, &MATRIX(*Y, 0, i), vc);+            norm = 1.0 / igraph_blas_dnrm2(&v);+            igraph_vector_scale(&v, norm);+        }+    } else if (Y) {+        IGRAPH_CHECK(igraph_matrix_update(Y, X));+    }++    if (zapsmall) {+        igraph_vector_zapsmall(&tmpD, 0);+        igraph_matrix_zapsmall(X, 0);+        if (Y) {+            igraph_matrix_zapsmall(Y, 0);+        }+    }++    if (D) {+        igraph_vector_update(D, &tmpD);+        if (!eigen) {+            for (i = 0; i < no; i++) {+                VECTOR(*D)[i] = sqrt(VECTOR(*D)[i]);+            }+        }+    }++    if (scaled) {+        if (eigen) {+            /* eigenvalues were calculated */+            for (i = 0; i < no; i++) {+                VECTOR(tmpD)[i] = sqrt(fabs(VECTOR(tmpD)[i]));+            }+        } else {+            /* singular values were calculated */+            for (i = 0; i < no; i++) {+                VECTOR(tmpD)[i] = sqrt(sqrt(VECTOR(tmpD)[i]));+            }+        }++        for (j = 0; j < vc; j++) {+            for (i = 0; i < no; i++) {+                MATRIX(*X, j, i) *= VECTOR(tmpD)[i];+            }+        }++        if (Y) {+            for (j = 0; j < vc; j++) {+                for (i = 0; i < no; i++) {+                    MATRIX(*Y, j, i) *= VECTOR(tmpD)[i];+                }+            }+        }+    }++    igraph_vector_destroy(&tmpD);+    if (!weights) {+        if (!symmetric) {+            igraph_adjlist_destroy(&inlist);+            IGRAPH_FINALLY_CLEAN(1);+        }+        igraph_adjlist_destroy(&outlist);+    } else {+        if (!symmetric) {+            igraph_inclist_destroy(&einlist);+            IGRAPH_FINALLY_CLEAN(1);+        }+        igraph_inclist_destroy(&eoutlist);+    }+    igraph_vector_destroy(&tmp);+    IGRAPH_FINALLY_CLEAN(3);++    return 0;+}++/**+ * \function igraph_adjacency_spectral_embedding+ * Adjacency spectral embedding+ *+ * Spectral decomposition of the adjacency matrices of graphs.+ * This function computes a \code{no}-dimensional Euclidean+ * representation of the graph based on its adjacency+ * matrix, A. This representation is computed via the singular value+ * decomposition of the adjacency matrix, A=UDV^T. In the case,+ * where the graph is a random dot product graph generated using latent+ * position vectors in R^no for each vertex, the embedding will+ * provide an estimate of these latent vectors.+ *+ * </para><para>+ * For undirected graphs the latent positions are calculated as+ * X=U^no D^(1/2) where U^no equals to the first no columns of U, and+ * D^(1/2) is a diagonal matrix containing the square root of the selected+ * singular values on the diagonal.+ *+ * </para><para>+ * For directed graphs the embedding is defined as the pair+ * X=U^no D^(1/2), Y=V^no D^(1/2). (For undirected graphs U=V,+ * so it is enough to keep one of them.)+ *+ * \param graph The input graph, can be directed or undirected.+ * \param no An integer scalar. This value is the embedding dimension of+ *        the spectral embedding. Should be smaller than the number of+ *        vertices. The largest no-dimensional non-zero+ *        singular values are used for the spectral embedding.+ * \param weights Optional edge weights. Supply a null pointer for+ *        unweighted graphs.+ * \param which Which eigenvalues (or singular values, for directed+ *        graphs) to use, possible values:+ *        \clist+ *          \cli IGRAPH_EIGEN_LM+ *          the ones with the largest magnitude+ *          \cli IGRAPH_EIGEN_LA+ *          the (algebraic) largest ones+ *          \cli IGRAPH_EIGEN_SA+ *          the (algebraic) smallest ones.+ *        \endclist+ *        For directed graphs, <code>IGRAPH_EIGEN_LM</code> and+ *        <code>IGRAPH_EIGEN_LA</code> are the same because singular+ *        values are used for the ordering instead of eigenvalues.+ * \param scaled Whether to return X and Y (if scaled is non-zero), or+ *        U and V.+ * \param X Initialized matrix, the estimated latent positions are+ *        stored here.+ * \param Y Initialized matrix or a null pointer. If not a null+ *        pointer, then the second half of the latent positions are+ *        stored here. (For undirected graphs, this always equals X.)+ * \param D Initialized vector or a null pointer. If not a null+ *        pointer, then the eigenvalues (for undirected graphs) or the+ *        singular values (for directed graphs) are stored here.+ * \param cvec A numeric vector, its length is the number vertices in the+ *        graph. This vector is added to the diagonal of the adjacency+ *        matrix, before performing the SVD.+ * \param options Options to ARPACK. See \ref igraph_arpack_options_t+ *        for details. Note that the function overwrites the+ *        <code>n</code> (number of vertices), <code>nev</code> and+ *        <code>which</code> parameters and it always starts the+ *        calculation from a random start vector.+ * \return Error code.+ *+ */++int igraph_adjacency_spectral_embedding(const igraph_t *graph,+                                        igraph_integer_t no,+                                        const igraph_vector_t *weights,+                                        igraph_eigen_which_position_t which,+                                        igraph_bool_t scaled,+                                        igraph_matrix_t *X,+                                        igraph_matrix_t *Y,+                                        igraph_vector_t *D,+                                        const igraph_vector_t *cvec,+                                        igraph_arpack_options_t *options) {++    igraph_arpack_function_t *callback, *callback_right;+    igraph_bool_t directed = igraph_is_directed(graph);++    if (directed) {+        callback = weights ? igraph_i_asembeddingw : igraph_i_asembedding;+        callback_right = (weights ? igraph_i_asembeddingw_right :+                          igraph_i_asembedding_right);+    } else {+        callback = weights ? igraph_i_asembeddinguw : igraph_i_asembeddingu;+        callback_right = 0;+    }++    return igraph_i_spectral_embedding(graph, no, weights, which, scaled,+                                       X, Y, D, cvec, /* deg2=*/ 0,+                                       options, callback, callback_right,+                                       /*symmetric=*/ !directed,+                                       /*eigen=*/ !directed, /*zapsmall=*/ 1);+}++int igraph_i_lse_und(const igraph_t *graph,+                     igraph_integer_t no,+                     const igraph_vector_t *weights,+                     igraph_eigen_which_position_t which,+                     igraph_neimode_t degmode,+                     igraph_laplacian_spectral_embedding_type_t type,+                     igraph_bool_t scaled,+                     igraph_matrix_t *X,+                     igraph_matrix_t *Y,+                     igraph_vector_t *D,+                     igraph_arpack_options_t *options) {++    igraph_arpack_function_t *callback;+    igraph_vector_t deg;++    switch (type) {+    case IGRAPH_EMBEDDING_D_A:+        callback = weights ? igraph_i_lsembedding_daw : igraph_i_lsembedding_da;+        break;+    case IGRAPH_EMBEDDING_DAD:+        callback = weights ? igraph_i_lsembedding_dadw : igraph_i_lsembedding_dad;+        break;+    case IGRAPH_EMBEDDING_I_DAD:+        callback = weights ? igraph_i_lsembedding_idadw : igraph_i_lsembedding_idad;+        break;+    default:+        IGRAPH_ERROR("Invalid Laplacian spectral embedding type",+                     IGRAPH_EINVAL);+        break;+    }++    IGRAPH_VECTOR_INIT_FINALLY(&deg, 0);+    igraph_strength(graph, &deg, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1,+                    weights);++    switch (type) {+    case IGRAPH_EMBEDDING_D_A:+        break;+    case IGRAPH_EMBEDDING_DAD:+    case IGRAPH_EMBEDDING_I_DAD: {+        int i, n = igraph_vector_size(&deg);+        for (i = 0; i < n; i++) {+            VECTOR(deg)[i] = 1.0 / sqrt(VECTOR(deg)[i]);+        }+    }+    break;+    default:+        break;+    }++    IGRAPH_CHECK(igraph_i_spectral_embedding(graph, no, weights, which,+                 scaled, X, Y, D, /*cvec=*/ &deg, /*deg2=*/ 0,+                 options, callback, 0, /*symmetric=*/ 1,+                 /*eigen=*/ 1, /*zapsmall=*/ 1));++    igraph_vector_destroy(&deg);+    IGRAPH_FINALLY_CLEAN(1);++    return 0;+}++int igraph_i_lse_dir(const igraph_t *graph,+                     igraph_integer_t no,+                     const igraph_vector_t *weights,+                     igraph_eigen_which_position_t which,+                     igraph_neimode_t degmode,+                     igraph_laplacian_spectral_embedding_type_t type,+                     igraph_bool_t scaled,+                     igraph_matrix_t *X,+                     igraph_matrix_t *Y,+                     igraph_vector_t *D,+                     igraph_arpack_options_t *options) {++    igraph_arpack_function_t *callback =+        weights ? igraph_i_lseembedding_oapw : igraph_i_lseembedding_oap;+    igraph_arpack_function_t *callback_right =+        weights ? igraph_i_lseembedding_oapw_right :+        igraph_i_lseembedding_oap_right;+    igraph_vector_t deg_in, deg_out;+    int i, n = igraph_vcount(graph);++    if (type != IGRAPH_EMBEDDING_OAP) {+        IGRAPH_ERROR("Invalid Laplacian spectral embedding type", IGRAPH_EINVAL);+    }++    IGRAPH_VECTOR_INIT_FINALLY(&deg_in, n);+    IGRAPH_VECTOR_INIT_FINALLY(&deg_out, n);+    igraph_strength(graph, &deg_in, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1,+                    weights);+    igraph_strength(graph, &deg_out, igraph_vss_all(), IGRAPH_OUT, /*loops=*/ 1,+                    weights);++    for (i = 0; i < n; i++) {+        VECTOR(deg_in)[i] = 1.0 / sqrt(VECTOR(deg_in)[i]);+        VECTOR(deg_out)[i] = 1.0 / sqrt(VECTOR(deg_out)[i]);+    }++    IGRAPH_CHECK(igraph_i_spectral_embedding(graph, no, weights, which,+                 scaled, X, Y, D, /*cvec=*/ &deg_in,+                 /*deg2=*/ &deg_out, options, callback,+                 callback_right, /*symmetric=*/ 0, /*eigen=*/ 0,+                 /*zapsmall=*/ 1));++    igraph_vector_destroy(&deg_in);+    igraph_vector_destroy(&deg_out);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}++/**+ * \function igraph_laplacian_spectral_embedding+ * Spectral embedding of the Laplacian of a graph+ *+ * This function essentially does the same as+ * \ref igraph_adjacency_spectral_embedding, but works on the Laplacian+ * of the graph, instead of the adjacency matrix.+ * \param graph The input graph.+ * \param no The number of eigenvectors (or singular vectors if the graph+ *        is directed) to use for the embedding.+ * \param weights Optional edge weights. Supply a null pointer for+ *        unweighted graphs.+ * \param which Which eigenvalues (or singular values, for directed+ *        graphs) to use, possible values:+ *        \clist+ *          \cli IGRAPH_EIGEN_LM+ *          the ones with the largest magnitude+ *          \cli IGRAPH_EIGEN_LA+ *          the (algebraic) largest ones+ *          \cli IGRAPH_EIGEN_SA+ *          the (algebraic) smallest ones.+ *        \endclist+ *        For directed graphs, <code>IGRAPH_EIGEN_LM</code> and+ *        <code>IGRAPH_EIGEN_LA</code> are the same because singular+ *        values are used for the ordering instead of eigenvalues.+ * \param type The type of the Laplacian to use. Various definitions+ *        exist for the Laplacian of a graph, and one can choose+ *        between them with this argument. Possible values:+ *        \clist+ *          \cli IGRAPH_EMBEDDING_D_A+ *           means D - A where D is the+ *           degree matrix and A is the adjacency matrix+ *          \cli IGRAPH_EMBEDDING_DAD+ *           means Di times A times Di,+ *           where Di is the inverse of the square root of the degree matrix;+ *          \cli IGRAPH_EMBEDDING_I_DAD+ *          means I - Di A Di, where I+ *          is the identity matrix.+ *        \endclist+ * \param scaled Whether to return X and Y (if scaled is non-zero), or+ *        U and V.+ * \param X Initialized matrix, the estimated latent positions are+ *        stored here.+ * \param Y Initialized matrix or a null pointer. If not a null+ *        pointer, then the second half of the latent positions are+ *        stored here. (For undirected graphs, this always equals X.)+ * \param D Initialized vector or a null pointer. If not a null+ *        pointer, then the eigenvalues (for undirected graphs) or the+ *        singular values (for directed graphs) are stored here.+ * \param options Options to ARPACK. See \ref igraph_arpack_options_t+ *        for details. Note that the function overwrites the+ *        <code>n</code> (number of vertices), <code>nev</code> and+ *        <code>which</code> parameters and it always starts the+ *        calculation from a random start vector.+ * \return Error code.+ *+ * \sa \ref igraph_adjacency_spectral_embedding to embed the adjacency+ * matrix.+ */++int igraph_laplacian_spectral_embedding(const igraph_t *graph,+                                        igraph_integer_t no,+                                        const igraph_vector_t *weights,+                                        igraph_eigen_which_position_t which,+                                        igraph_neimode_t degmode,+                                        igraph_laplacian_spectral_embedding_type_t type,+                                        igraph_bool_t scaled,+                                        igraph_matrix_t *X,+                                        igraph_matrix_t *Y,+                                        igraph_vector_t *D,+                                        igraph_arpack_options_t *options) {++    if (igraph_is_directed(graph)) {+        return igraph_i_lse_dir(graph, no, weights, which, degmode, type, scaled,+                                X, Y, D, options);+    } else {+        return igraph_i_lse_und(graph, no, weights, which, degmode, type, scaled,+                                X, Y, D, options);+    }+}++/**+ * \function igraph_dim_select+ * Dimensionality selection+ *+ * Dimensionality selection for singular values using+ * profile likelihood.+ *+ * </para><para>+ * The input of the function is a numeric vector which contains+ * the measure of "importance" for each dimension.+ *+ * </para><para>+ * For spectral embedding, these are the singular values of the adjacency+ * matrix. The singular values are assumed to be generated from a+ * Gaussian mixture distribution with two components that have different+ * means and same variance. The dimensionality d is chosen to+ * maximize the likelihood when the d largest singular values are+ * assigned to one component of the mixture and the rest of the singular+ * values assigned to the other component.+ *+ * </para><para>+ * This function can also be used for the general separation problem,+ * where we assume that the left and the right of the vector are coming+ * from two Normal distributions, with different means, and we want+ * to know their border.+ *+ * \param sv A numeric vector, the ordered singular values.+ * \param dim The result is stored here.+ * \return Error code.+ *+ * Time complexity: O(n), n is the number of values in sv.+ *+ * \sa \ref igraph_adjacency_spectral_embedding().+ */++int igraph_dim_select(const igraph_vector_t *sv, igraph_integer_t *dim) {++    int i, n = igraph_vector_size(sv);+    igraph_real_t x, x2, sum1 = 0.0, sum2 = igraph_vector_sum(sv);+    igraph_real_t sumsq1 = 0.0, sumsq2 = 0.0; /* to be set */+    igraph_real_t oldmean1, oldmean2, mean1 = 0.0, mean2 = sum2 / n;+    igraph_real_t varsq1 = 0.0, varsq2 = 0.0; /* to be set */+    igraph_real_t var1, var2, sd, profile, max = IGRAPH_NEGINFINITY;++    if (n == 0) {+        IGRAPH_ERROR("Need at least one singular value for dimensionality "+                     "selection", IGRAPH_EINVAL);+    }++    if (n == 1) {+        *dim = 1;+        return 0;+    }++    for (i = 0; i < n; i++) {+        x = VECTOR(*sv)[i];+        sumsq2 += x * x;+        varsq2 += (mean2 - x) * (mean2 - x);+    }++    for (i = 0; i < n - 1; i++) {+        int n1 = i + 1, n2 = n - i - 1, n1m1 = n1 - 1, n2m1 = n2 - 1;+        x = VECTOR(*sv)[i]; x2 = x * x;+        sum1 += x; sum2 -= x;+        sumsq1 += x2; sumsq2 -= x2;+        oldmean1 = mean1; oldmean2 = mean2;+        mean1 = sum1 / n1; mean2 = sum2 / n2;+        varsq1 += (x - oldmean1) * (x - mean1);+        varsq2 -= (x - oldmean2) * (x - mean2);+        var1 = i == 0 ? 0 : varsq1 / n1m1;+        var2 = i == n - 2 ? 0 : varsq2 / n2m1;+        sd = sqrt(( n1m1 * var1 + n2m1 * var2) / (n - 2));+        profile = /* - n * log(2.0*M_PI)/2.0 */ /* This is redundant */+            - n * log(sd) -+            ((sumsq1 - 2 * mean1 * sum1 + n1 * mean1 * mean1) ++             (sumsq2 - 2 * mean2 * sum2 + n2 * mean2 * mean2)) / 2.0 / sd / sd;+        if (profile > max) {+            max = profile;+            *dim = n1;+        }+    }++    /* Plus the last case, all elements in one group */+    x = VECTOR(*sv)[n - 1];+    sum1 += x;+    oldmean1 = mean1;+    mean1 = sum1 / n;+    sumsq1 += x * x;+    varsq1 += (x - oldmean1) * (x - mean1);+    var1 = varsq1 / (n - 1);+    sd = sqrt(var1);+    profile = /* - n * log(2.0*M_PI)/2.0 */ /* This is redundant */+        - n * log(sd) -+        (sumsq1 - 2 * mean1 * sum1 + n * mean1 * mean1) / 2.0 / sd / sd;+    if (profile > max) {+        max = profile;+        *dim = n;+    }++    return 0;+}
+ igraph/src/endfile.c view
@@ -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
+ igraph/src/erf_.c view
@@ -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
+ igraph/src/erfc_.c view
@@ -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
+ igraph/src/err.c view
@@ -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
+ igraph/src/error.c view
@@ -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) {+}
+ igraph/src/etime_.c view
@@ -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
+ igraph/src/exit_.c view
@@ -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
+ igraph/src/f77_aloc.c view
@@ -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
+ igraph/src/f77vers.c view
@@ -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.+*/
+ igraph/src/fast_community.c view
@@ -0,0 +1,1067 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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, *best;+    igraph_real_t bestdq, currdq;++    n = igraph_vector_ptr_size(&comm->neis);+    if (n == 0) {+        comm->maxdq = 0;+        return 1;+    }++    best = (igraph_i_fastgreedy_commpair*)VECTOR(comm->neis)[0];+    bestdq = *best->dq;+    for (i = 1; i < n; i++) {+        p = (igraph_i_fastgreedy_commpair*)VECTOR(comm->neis)[i];+        currdq = *p->dq;+        if (currdq > bestdq) {+            best = p;+            bestdq = currdq;+        }+    }++    if (best != comm->maxdq) {+        comm->maxdq = best;+        return 1;+    } else {+        return 0;+    }+}++/* 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;+    igraph_i_fastgreedy_community** heap = list->heap;+    igraph_integer_t* heapindex = list->heapindex;++    root = idx;+    while (root * 2 + 1 < list->no_of_communities) {+        child = root * 2 + 1;+        if (child + 1 < list->no_of_communities &&+            *heap[child]->maxdq->dq < *heap[child + 1]->maxdq->dq) {+            child++;+        }+        if (*heap[root]->maxdq->dq < *heap[child]->maxdq->dq) {+            c1 = heap[root]->maxdq->first;+            c2 = heap[child]->maxdq->first;++            dummy = heap[root];+            heap[root] = heap[child];+            heap[child] = dummy;++            dummy2 = heapindex[c1];+            heapindex[c1] = heapindex[c2];+            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;+    igraph_i_fastgreedy_community** heap = list->heap;+    igraph_integer_t* heapindex = list->heapindex;++    root = idx;+    while (root > 0) {+        parent = (root - 1) / 2;+        if (*heap[parent]->maxdq->dq < *heap[root]->maxdq->dq) {+            c1 = heap[root]->maxdq->first;+            c2 = heap[parent]->maxdq->first;++            dummy = heap[parent];+            heap[parent] = heap[root];+            heap[root] = dummy;++            dummy2 = heapindex[c1];+            heapindex[c1] = heapindex[c2];+            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);+            }+        }+    }+}++/* 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);+}++/* Sorts the neighbor list of the community with the given index, optionally+ * optimizing the process if we know that the list is nearly sorted and only+ * a given pair is in the wrong place. */+void igraph_i_fastgreedy_community_sort_neighbors_of(+    igraph_i_fastgreedy_community_list* list, long int index,+    igraph_i_fastgreedy_commpair* changed_pair) {+    igraph_vector_ptr_t* vec;+    long int i, n;+    igraph_bool_t can_skip_sort = 0;+    igraph_i_fastgreedy_commpair *other_pair;++    vec = &list->e[index].neis;+    if (changed_pair != 0) {+        /* Optimized sorting */++        /* First we look for changed_pair in vec */+        n = igraph_vector_ptr_size(vec);+        for (i = 0; i < n; i++) {+            if (VECTOR(*vec)[i] == changed_pair) {+                break;+            }+        }++        /* Did we find it? We should have -- otherwise it's a bug */+        if (i >= n) {+            IGRAPH_WARNING("changed_pair not found in neighbor vector while re-sorting "+                           "the neighbors of a community; this is probably a bug. Falling back to "+                           "full sort instead."+                          );+        } else {+            /* Okay, the pair that changed is at index i. We need to figure out where+             * its new place should be. We can simply try moving the item all the way+             * to the left as long as the comparison function tells so (since the+             * rest of the vector is sorted), and then move all the way to the right+             * as long as the comparison function tells so, and we will be okay. */++            /* Shifting to the left */+            while (i > 0) {+                other_pair = VECTOR(*vec)[i - 1];+                if (other_pair->second > changed_pair->second) {+                    VECTOR(*vec)[i] = other_pair;+                    i--;+                } else {+                    break;+                }+            }+            VECTOR(*vec)[i] = changed_pair;++            /* Shifting to the right */+            while (i < n - 1) {+                other_pair = VECTOR(*vec)[i + 1];+                if (other_pair->second < changed_pair->second) {+                    VECTOR(*vec)[i] = other_pair;+                    i++;+                } else {+                    break;+                }+            }+            VECTOR(*vec)[i] = changed_pair;++            /* Mark that we don't need a full sort */+            can_skip_sort = 1;+        }+    }++    if (!can_skip_sort) {+        /* Fallback to full sorting */+        igraph_vector_ptr_sort(vec, igraph_i_fastgreedy_commpair_cmp);+    }+}++/* 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;+}++/**+ * \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, best_no_of_joins;+    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, bestq, weight_sum, loop_weight_sum;+    igraph_bool_t has_multiple;+    igraph_matrix_t merges_local;++    /*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 (membership != 0 && merges == 0) {+        /* We need the merge matrix because the user wants the membership+         * vector, so we allocate one on our own */+        IGRAPH_CHECK(igraph_matrix_init(&merges_local, total_joins, 2));+        IGRAPH_FINALLY(igraph_matrix_destroy, &merges_local);+        merges = &merges_local;+    }++    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_i_fastgreedy_community_sort_neighbors_of(&communities, i, 0);+        /* 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];+        }+    }++    /* Initialize "best modularity" value and best merge counter */+    bestq = q;+    best_no_of_joins = 0;++    /* 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;+        }++        /* Update best modularity if needed */+        if (q >= bestq) {+            bestq = q;+            best_no_of_joins = no_of_joins;+        }++        /* 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;+                    /* p2->opposite->second changed, so it means that+                     * communities.e[p2->second].neis (which contains p2->opposite) is+                     * not sorted any more. We have to find the index of p2->opposite in+                     * this vector and move it to the correct place. Moving should be an+                     * O(n) operation; re-sorting would be O(n*logn) or even worse,+                     * depending on the pivoting strategy used by qsort() since the+                     * vector is nearly sorted */+                    igraph_i_fastgreedy_community_sort_neighbors_of(+                        &communities, p2->second, p2->opposite);+                    /* 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` */+            igraph_i_fastgreedy_community_sort_neighbors_of(&communities, p2->second, p2->opposite);+            /* 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) {+        IGRAPH_CHECK(igraph_community_to_membership(merges,+                     (igraph_integer_t) no_of_nodes,+                     /*steps=*/ (igraph_integer_t) best_no_of_joins,+                     membership,+                     /*csize=*/ 0));+    }++    if (merges == &merges_local) {+        igraph_matrix_destroy(&merges_local);+        IGRAPH_FINALLY_CLEAN(1);+    }++    return 0;+}++#ifdef IGRAPH_FASTCOMM_DEBUG+    #undef IGRAPH_FASTCOMM_DEBUG+#endif++
+ igraph/src/feedback_arc_set.c view
@@ -0,0 +1,665 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+        if (k > 0) {+            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 */+        if (n > 1) {+            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+}+
+ igraph/src/flow.c view
@@ -0,0 +1,2532 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_int_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_int_size(edges);+            for (i = 0; i < n; i++) {+                igraph_integer_t edge = (igraph_integer_t) VECTOR(*edges)[i];+                igraph_integer_t to = (igraph_integer_t) VECTOR(*neis)[i];+                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_int_size(edges);+        for (i = 0; i < n; ) {+            if (VECTOR(*neis)[i] == last) {+                VECTOR(*neis)[i] = VECTOR(*neis)[n - 1];+                VECTOR(*edges)[i] = VECTOR(*edges)[n - 1];+                igraph_vector_int_pop_back(neis);+                igraph_vector_int_pop_back(edges);+                n--;+            } else {+                i++;+            }+        }++        edges = igraph_inclist_get(&inclist, last);+        neis = igraph_adjlist_get(&adjlist, last);+        n = igraph_vector_int_size(edges);+        for (i = 0; i < n; ) {+            if (VECTOR(*neis)[i] == a) {+                VECTOR(*neis)[i] = VECTOR(*neis)[n - 1];+                VECTOR(*edges)[i] = VECTOR(*edges)[n - 1];+                igraph_vector_int_pop_back(neis);+                igraph_vector_int_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_int_append(edges, edges2));+        IGRAPH_CHECK(igraph_vector_int_append(neis, neis2));+        igraph_vector_int_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;++    if (igraph_vcount(graph) == 0) {+        *res = 0;+        *found = 1;+        return 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;+    igraph_integer_t number_of_nodes = igraph_vcount(graph);++    /* igraph_mincut_value returns infinity for the singleton graph,+     * which cannot be cast to an integer. We catch this case early+     * and postulate the edge-connectivity of this graph to be 0.+     * This is consistent with what other software packages return. */+    if (number_of_nodes <= 1) {+        *res = 0;+        return 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;+}+
+ igraph/src/fmt.c view
@@ -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
+ igraph/src/fmtlib.c view
@@ -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
+ igraph/src/foreign-dl-lexer.c view
@@ -0,0 +1,2232 @@+#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 25+#define YY_END_OF_BUFFER 26+/* 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[131] =+    {   0,+        0,    0,    0,    0,    0,    0,   18,   18,   21,   21,+       26,   23,   22,    1,    1,    4,   23,   23,   23,   23,+       12,   23,    1,   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[140] =+    {   0,+        0,   22,   44,   64,   84,   94,  104,  114,  124,  134,+      288,  289,    4,  283,  283,    2,    1,  261,  270,   15,+       29,  289,  280,  289,   39,   50,    0,  289,   34,    0,+       52,   19,   64,    0,   54,   51,   74,  289,   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,  289,  246,  246,  189,  193,  195,+      197,  199,  205,  218,  209,  289,  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,  289,+      247,  250,  253,  256,  259,  262,    7,    6,    0+    } ;++static yyconst flex_int16_t yy_def[140] =+    {   0,+      131,  131,  132,  132,  133,  133,  134,  134,  135,  135,+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,+      136,  130,  130,  130,  136,  136,  137,  130,  137,  138,+      130,  138,  138,  139,  130,  139,  130,  130,  130,  130,+      130,  130,  130,  130,  130,  136,  130,  136,  136,  137,+      130,  138,  130,  138,  138,  138,  139,  130,  139,  130,+      130,  130,  130,  130,  136,  136,  138,  138,  138,  130,+      130,  130,  136,  136,  130,  130,  130,  136,  136,  130,+      130,  136,  130,  130,  130,  130,  130,   84,  130,  130,+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,++      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,+      130,  130,  130,  130,  130,  130,  130,  130,  130,    0,+      130,  130,  130,  130,  130,  130,  130,  130,  130+    } ;++static yyconst flex_int16_t yy_nxt[319] =+    {   0,+       57,   13,   14,   15,   13,   37,   52,   50,   37,   16,+       16,   39,   39,  130,   40,   17,   44,   18,  130,   44,+       19,   41,   20,   13,   14,   15,   13,   45,   54,   54,+       47,   16,   16,   47,  127,   51,  123,   17,   51,   18,+       47,  122,   19,   47,   20,   22,   14,   23,   24,  121,+       24,   47,   48,   53,   47,   58,   53,  120,   58,   25,+       59,   59,  119,   49,   26,   22,   14,   23,   24,  118,+       24,  117,   55,   54,   54,   37,   39,   39,   37,   25,+       56,   67,   67,  116,   26,   28,   14,   23,   28,   61,+       22,  115,   61,   29,   29,   28,   14,   23,   28,   64,++       22,  114,   64,   29,   29,   31,   14,   23,   31,   47,+       22,   32,   47,   33,   33,   31,   14,   23,   31,   47,+       22,   32,   47,   33,   33,   35,   14,   23,   35,   47,+       22,  113,   47,   36,   36,   35,   14,   23,   35,   44,+       22,  112,   44,   36,   36,   47,   51,  111,   47,   51,+       45,  110,   53,   58,   65,   53,   58,  109,   66,   55,+       54,   54,   59,   59,   68,  108,   68,   56,   69,   69,+       61,   64,   47,   61,   64,   47,   47,   69,   69,   47,+       67,   67,   69,   69,   73,   47,   47,   56,   47,   47,+       47,   74,  107,   47,   47,   78,   83,   47,   85,   83,++       87,   85,  106,   87,  105,   79,   83,   84,   86,   83,+       85,   87,  126,   85,   87,  126,  104,   84,   82,   88,+      124,  128,   88,  124,  128,   92,   92,  103,  124,  124,+      125,  124,  124,  126,   89,   90,  126,  102,  129,  128,+       91,  129,  128,  129,  101,  100,  129,   12,   12,   12,+       21,   21,   21,   27,   27,   27,   30,   30,   30,   34,+       34,   34,   46,   46,   99,   98,   97,   96,   95,   94,+       93,   81,   80,   77,   76,   75,   72,   71,   70,   63,+       62,   60,   38,   43,   42,   38,   38,  130,   11,  130,+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,++      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,+      130,  130,  130,  130,  130,  130,  130,  130+    } ;++static yyconst flex_int16_t yy_chk[319] =+    {   0,+      139,    1,    1,    1,    1,   13,  138,  137,   13,    1,+        1,   16,   16,    0,   17,    1,   20,    1,    0,   20,+        1,   17,    1,    2,    2,    2,    2,   20,   32,   32,+       21,    2,    2,   21,  122,   29,  119,    2,   29,    2,+       25,  118,    2,   25,    2,    3,    3,    3,    3,  117,+        3,   26,   25,   31,   26,   35,   31,  116,   35,    3,+       36,   36,  115,   26,    3,    4,    4,    4,    4,  114,+        4,  113,   33,   33,   33,   37,   39,   39,   37,    4,+       33,   55,   55,  112,    4,    5,    5,    5,    5,   41,+        5,  111,   41,    5,    5,    6,    6,    6,    6,   45,++        6,  110,   45,    6,    6,    7,    7,    7,    7,   46,+        7,    7,   46,    7,    7,    8,    8,    8,    8,   47,+        8,    8,   47,    8,    8,    9,    9,    9,    9,   48,+        9,  109,   48,    9,    9,   10,   10,   10,   10,   44,+       10,  108,   44,   10,   10,   49,   51,  107,   49,   51,+       44,  106,   53,   58,   48,   53,   58,  105,   49,   54,+       54,   54,   59,   59,   56,  104,   56,   54,   56,   56,+       61,   64,   65,   61,   64,   65,   66,   68,   68,   66,+       67,   67,   69,   69,   65,   73,   74,   67,   73,   74,+       78,   66,  103,   78,   79,   73,   80,   79,   81,   80,++       82,   81,  102,   82,  101,   74,   83,   80,   81,   83,+       85,   87,  121,   85,   87,  121,  100,   83,   79,   84,+      120,  123,   84,  120,  123,   85,   87,   99,  124,  125,+      120,  124,  125,  126,   84,   84,  126,   98,  127,  128,+       84,  127,  128,  129,   97,   96,  129,  131,  131,  131,+      132,  132,  132,  133,  133,  133,  134,  134,  134,  135,+      135,  135,  136,  136,   95,   94,   93,   92,   91,   90,+       89,   77,   76,   72,   71,   70,   63,   62,   60,   43,+       42,   40,   23,   19,   18,   15,   14,   11,  130,  130,+      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,++      130,  130,  130,  130,  130,  130,  130,  130,  130,  130,+      130,  130,  130,  130,  130,  130,  130,  130+    } ;++/* 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 "../../src/foreign-dl-lexer.l"+/* +   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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 "../../src/foreign-dl-lexer.l"++/* +   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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 "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. */+#ifdef USING_R+#define fprintf(file, msg, ...) (1)+#endif+#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 606 "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 81 "../../src/foreign-dl-lexer.l"+++#line 852 "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 >= 131 )+					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:+/* rule 1 can match eol */+YY_RULE_SETUP+#line 83 "../../src/foreign-dl-lexer.l"+{ return NEWLINE; }+	YY_BREAK+case 2:+YY_RULE_SETUP+#line 85 "../../src/foreign-dl-lexer.l"+{ return DL; }+	YY_BREAK+case 3:+YY_RULE_SETUP+#line 86 "../../src/foreign-dl-lexer.l"+{+  return NEQ; }+	YY_BREAK+case 4:+YY_RULE_SETUP+#line 88 "../../src/foreign-dl-lexer.l"+{ return NUM; }+	YY_BREAK+case 5:+YY_RULE_SETUP+#line 90 "../../src/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 101 "../../src/foreign-dl-lexer.l"+{ BEGIN(LABELM); return LABELS; }+	YY_BREAK+case 7:+YY_RULE_SETUP+#line 102 "../../src/foreign-dl-lexer.l"+{+  return LABELSEMBEDDED; }+	YY_BREAK+case 8:+YY_RULE_SETUP+#line 104 "../../src/foreign-dl-lexer.l"+{+  yyextra->mode=0; return FORMATFULLMATRIX; }+	YY_BREAK+case 9:+YY_RULE_SETUP+#line 106 "../../src/foreign-dl-lexer.l"+{+  yyextra->mode=1; return FORMATEDGELIST1; }+	YY_BREAK+case 10:+YY_RULE_SETUP+#line 108 "../../src/foreign-dl-lexer.l"+{+  yyextra->mode=2; return FORMATNODELIST1; }+	YY_BREAK+case 11:+YY_RULE_SETUP+#line 111 "../../src/foreign-dl-lexer.l"+{ /* eaten up */ }+	YY_BREAK+case 12:+YY_RULE_SETUP+#line 112 "../../src/foreign-dl-lexer.l"+{ return LABEL; }+	YY_BREAK+case 13:+YY_RULE_SETUP+#line 114 "../../src/foreign-dl-lexer.l"+{ return DIGIT; }+	YY_BREAK+case 14:+YY_RULE_SETUP+#line 115 "../../src/foreign-dl-lexer.l"+{ return LABEL; }+	YY_BREAK+case 15:+YY_RULE_SETUP+#line 116 "../../src/foreign-dl-lexer.l"+{ }+	YY_BREAK+case 16:+YY_RULE_SETUP+#line 118 "../../src/foreign-dl-lexer.l"+{ return NUM; }+	YY_BREAK+case 17:+YY_RULE_SETUP+#line 119 "../../src/foreign-dl-lexer.l"+{ return LABEL; }+	YY_BREAK+case 18:+YY_RULE_SETUP+#line 120 "../../src/foreign-dl-lexer.l"+{ }+	YY_BREAK+case 19:+YY_RULE_SETUP+#line 122 "../../src/foreign-dl-lexer.l"+{ return NUM; }+	YY_BREAK+case 20:+YY_RULE_SETUP+#line 123 "../../src/foreign-dl-lexer.l"+{ return LABEL; }+	YY_BREAK+case 21:+YY_RULE_SETUP+#line 124 "../../src/foreign-dl-lexer.l"+{ }+	YY_BREAK+case 22:+YY_RULE_SETUP+#line 126 "../../src/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 128 "../../src/foreign-dl-lexer.l"+{ +                          if (yyextra->eof) {+			    yyterminate();+			  } else {+			    yyextra->eof=1;+			    BEGIN(INITIAL);+			    return EOFF;+			  }			  +                        }+	YY_BREAK+case 23:+YY_RULE_SETUP+#line 138 "../../src/foreign-dl-lexer.l"+{ return 0; }+	YY_BREAK+case 24:+YY_RULE_SETUP+#line 140 "../../src/foreign-dl-lexer.l"+{ return ERROR; }+	YY_BREAK+case 25:+YY_RULE_SETUP+#line 141 "../../src/foreign-dl-lexer.l"+YY_FATAL_ERROR( "flex scanner jammed" );+	YY_BREAK+#line 1095 "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 >= 131 )+				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 >= 131 )+			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 == 130);++	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 141 "../../src/foreign-dl-lexer.l"
+ igraph/src/foreign-dl-parser.c view
@@ -0,0 +1,2145 @@+/* 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,+     ERROR = 271+   };+#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+#define ERROR 271+++++/* Copy the first part of user declarations.  */+#line 23 "../../src/foreign-dl-parser.y"+++/* +   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@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 "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 86 "../../src/foreign-dl-parser.y"+{+  long int integer;+  igraph_real_t real;+}+/* Line 193 of yacc.c.  */+#line 195 "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 220 "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  17+/* YYNNTS -- Number of nonterminals.  */+#define YYNNTS  37+/* YYNRULES -- Number of rules.  */+#define YYNRULES  66+/* YYNRULES -- Number of states.  */+#define YYNSTATES  138++/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */+#define YYUNDEFTOK  2+#define YYMAXUTOK   271++#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+};++#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,    97,   105,   111,   121,   131,   132,+     135,   140,   144,   146,   147,   150,   155,   159,   161,   163,+     167,   170,   178,   184,   194,   204,   205,   208,   212,   214,+     215,   218,   219,   222,   226,   228,   229+};++/* YYRHS -- A `-1'-separated list of the rules' RHS.  */+static const yytype_int8 yyrhs[] =+{+      18,     0,    -1,     5,     6,    39,     4,    21,    19,    20,+      -1,    -1,    19,    23,    -1,    -1,    15,    -1,    22,    -1,+      35,    -1,    44,    -1,    10,    23,    24,    -1,    24,    -1,+      -1,     4,    -1,     7,    23,    26,    -1,     8,    23,    25,+      23,     7,    23,    26,    -1,     9,    23,     7,    23,    29,+      -1,    -1,    25,    23,    14,    -1,    -1,    26,    27,     4,+      -1,    -1,    27,    28,    -1,    13,    -1,    30,    -1,    31,+       4,    33,    -1,    -1,    31,    23,    32,    -1,    14,    -1,+      34,    -1,    33,    34,    -1,    14,    27,     4,    -1,    11,+      23,    36,    -1,     7,    23,    37,    -1,     8,    23,    25,+      23,     7,    23,    37,    -1,     9,    23,     7,    23,    40,+      -1,     8,    23,    25,    23,     9,    23,     7,    23,    40,+      -1,     9,    23,     8,    23,    25,    23,     7,    23,    40,+      -1,    -1,    37,    38,    -1,    39,    39,    42,     4,    -1,+      39,    39,     4,    -1,     3,    -1,    -1,    40,    41,    -1,+      43,    43,    42,     4,    -1,    43,    43,     4,    -1,     3,+      -1,    14,    -1,    12,    23,    45,    -1,     7,    46,    -1,+       8,    23,    25,    23,     7,    23,    46,    -1,     9,    23,+       7,    23,    50,    -1,     8,    23,    25,    23,     9,    23,+       7,    23,    50,    -1,     9,    23,     8,    23,    25,    23,+       7,    23,    50,    -1,    -1,    46,    47,    -1,    48,    49,+       4,    -1,     3,    -1,    -1,    49,    39,    -1,    -1,    50,+      51,    -1,    52,    53,     4,    -1,    43,    -1,    -1,    53,+      43,    -1+};++/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */+static const yytype_uint16 yyrline[] =+{+       0,   111,   111,   113,   113,   115,   115,   117,   118,   119,+     122,   122,   124,   124,   126,   127,   128,   131,   132,   138,+     138,   143,   143,   145,   155,   157,   159,   159,   161,   165,+     169,   174,   178,   180,   181,   182,   183,   184,   187,   188,+     191,   193,   197,   200,   201,   204,   206,   210,   213,   229,+     231,   232,   233,   234,   235,   238,   239,   242,   244,   247,+     247,   253,   254,   257,   259,   263,   263+};+#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", "ERROR", "$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,   271+};+# endif++/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */+static const yytype_uint8 yyr1[] =+{+       0,    17,    18,    19,    19,    20,    20,    21,    21,    21,+      22,    22,    23,    23,    24,    24,    24,    25,    25,    26,+      26,    27,    27,    28,    29,    30,    31,    31,    32,    33,+      33,    34,    35,    36,    36,    36,    36,    36,    37,    37,+      38,    38,    39,    40,    40,    41,    41,    42,    43,    44,+      45,    45,    45,    45,    45,    46,    46,    47,    48,    49,+      49,    50,    50,    51,    52,    53,    53+};++/* 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,     3,     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,    12,    12,    12,    32,    55,    12,    12,    49,     6,+       2,     4,     0,     0,    26,    38,    17,     0,    50,    17,+       0,    20,    23,    22,    12,    18,    16,    24,    12,    33,+      12,    12,    12,    58,    56,    59,    12,    12,    12,    19,+       0,     0,    39,     0,     0,    43,    17,     0,     0,    61,+      17,    15,    21,    25,    29,    28,    27,     0,    12,    12,+      35,    12,    57,    60,    12,    12,    52,    12,     0,    30,+      47,    41,     0,    38,     0,    48,    44,     0,     0,    55,+       0,    64,    62,    65,     0,    31,    40,    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,+      59,    72,    73,    90,   106,   102,   107,    18,    38,    48,+      64,    65,    77,    96,   112,   113,   123+};++/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing+   STATE-NUM.  */+#define YYPACT_NINF -114+static const yytype_int8 yypact[] =+{+       8,    38,    11,    43,  -114,  -114,    44,    57,    46,    46,+      46,    46,    46,    46,  -114,  -114,  -114,  -114,  -114,  -114,+    -114,  -114,    69,    53,    63,    66,     6,    65,    46,    46,+    -114,    46,    46,    46,  -114,  -114,    46,    46,  -114,  -114,+    -114,  -114,     5,    19,  -114,  -114,  -114,    76,    84,  -114,+      82,  -114,  -114,  -114,    46,  -114,  -114,  -114,    93,    43,+      46,    46,    46,  -114,  -114,  -114,    46,    46,    46,  -114,+      85,    86,  -114,    43,    23,  -114,  -114,    88,    33,  -114,+    -114,    65,  -114,    85,  -114,  -114,  -114,    90,    46,    46,+      87,    46,  -114,  -114,    46,    46,    87,    46,    25,  -114,+    -114,  -114,    94,  -114,    95,  -114,  -114,    87,    29,  -114,+      96,  -114,  -114,  -114,    49,  -114,  -114,    43,    46,    92,+      46,    84,    46,     2,    46,  -114,  -114,   100,  -114,  -114,+    -114,  -114,  -114,    87,  -114,    87,    87,    87+};++/* YYPGOTO[NTERM-NUM].  */+static const yytype_int8 yypgoto[] =+{+    -114,  -114,  -114,  -114,  -114,  -114,    -9,    83,   -41,    36,+      26,  -114,  -114,  -114,  -114,  -114,  -114,    24,  -114,  -114,+       7,  -114,     4,  -113,  -114,    -7,   -82,  -114,  -114,     9,+    -114,  -114,  -114,   -98,  -114,  -114,  -114+};++/* 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,    60,   130,     6,    66,    51,+      19,     4,   133,     1,   111,   135,   105,    41,    52,    43,+      44,    39,    45,    46,    47,   119,    54,    49,    50,   115,+      88,   136,    89,    55,   137,    91,   120,    55,    52,    97,+      94,   131,    95,    55,     3,    69,     5,    55,     7,    71,+      19,    74,    75,    76,   111,   111,   124,    78,    79,    80,+       8,     9,    10,    55,     8,     9,    10,    11,    12,    13,+      31,    32,    33,    35,    36,    37,    29,    87,   -21,   103,+     104,    93,   108,    61,    62,   109,   110,    63,   114,    67,+      68,     5,    92,   100,   101,   100,   126,    70,   116,    82,+      85,   105,   118,   122,   134,    81,    30,    99,    98,   125,+     117,   128,   127,   129,     0,   132,     0,     0,   121+};++static const yytype_int16 yycheck[] =+{+       9,    10,    11,    12,    13,    46,     4,     3,    49,     4,+       4,     0,   125,     5,    96,   128,    14,    26,    13,    28,+      29,    15,    31,    32,    33,   107,     7,    36,    37,     4,+       7,   129,     9,    14,   132,    76,     7,    14,    13,    80,+       7,   123,     9,    14,     6,    54,     3,    14,     4,    58,+       4,    60,    61,    62,   136,   137,     7,    66,    67,    68,+       7,     8,     9,    14,     7,     8,     9,    10,    11,    12,+       7,     8,     9,     7,     8,     9,     7,    73,    13,    88,+      89,    77,    91,     7,     8,    94,    95,     3,    97,     7,+       8,     3,     4,     3,     4,     3,     4,     4,     4,    14,+      14,    14,     7,     7,     4,    69,    23,    83,    82,   118,+     103,   120,   119,   122,    -1,   124,    -1,    -1,   109+};++/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing+   symbol of state STATE-NUM.  */+static const yytype_uint8 yystos[] =+{+       0,     5,    18,     6,     0,     3,    39,     4,     7,     8,+       9,    10,    11,    12,    21,    22,    24,    35,    44,     4,+      23,    23,    23,    23,    23,    23,    19,    26,    25,     7,+      24,     7,     8,     9,    36,     7,     8,     9,    45,    15,+      20,    23,    27,    23,    23,    23,    23,    23,    46,    23,+      23,     4,    13,    28,     7,    14,    29,    30,    31,    37,+      25,     7,     8,     3,    47,    48,    25,     7,     8,    23,+       4,    23,    38,    39,    23,    23,    23,    49,    23,    23,+      23,    26,    14,    33,    34,    14,    32,    39,     7,     9,+      40,    25,     4,    39,     7,     9,    50,    25,    27,    34,+       3,     4,    42,    23,    23,    14,    41,    43,    23,    23,+      23,    43,    51,    52,    23,     4,     4,    37,     7,    43,+       7,    46,     7,    53,     7,    23,     4,    42,    23,    23,+       4,    43,    23,    40,     4,    40,    50,    50+};++#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 111 "../../src/foreign-dl-parser.y"+    { context->n=(yyvsp[(3) - (7)].integer); }+    break;++  case 7:+#line 117 "../../src/foreign-dl-parser.y"+    { context->type=IGRAPH_DL_MATRIX; }+    break;++  case 8:+#line 118 "../../src/foreign-dl-parser.y"+    { context->type=IGRAPH_DL_EDGELIST1; }+    break;++  case 9:+#line 119 "../../src/foreign-dl-parser.y"+    { context->type=IGRAPH_DL_NODELIST1; }+    break;++  case 10:+#line 122 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 11:+#line 122 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 14:+#line 126 "../../src/foreign-dl-parser.y"+    { }+    break;++  case 15:+#line 127 "../../src/foreign-dl-parser.y"+    { }+    break;++  case 16:+#line 128 "../../src/foreign-dl-parser.y"+    { }+    break;++  case 17:+#line 131 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 18:+#line 132 "../../src/foreign-dl-parser.y"+    { +	      igraph_i_dl_add_str(igraph_dl_yyget_text(scanner), +                                  igraph_dl_yyget_leng(scanner), +				  context); }+    break;++  case 19:+#line 138 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 20:+#line 138 "../../src/foreign-dl-parser.y"+    {+  context->from += 1;+  context->to = 0;+ }+    break;++  case 22:+#line 143 "../../src/foreign-dl-parser.y"+    { }+    break;++  case 23:+#line 145 "../../src/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 155 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 25:+#line 157 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 28:+#line 161 "../../src/foreign-dl-parser.y"+    { igraph_i_dl_add_str(igraph_dl_yyget_text(scanner), +                                   igraph_dl_yyget_leng(scanner), +				   context); }+    break;++  case 29:+#line 165 "../../src/foreign-dl-parser.y"+    {+	         context->from += 1; +		 context->to = 0;+               }+    break;++  case 30:+#line 169 "../../src/foreign-dl-parser.y"+    { +	         context->from += 1; +		 context->to = 0;+               }+    break;++  case 31:+#line 174 "../../src/foreign-dl-parser.y"+    { }+    break;++  case 32:+#line 178 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 33:+#line 180 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 34:+#line 181 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 35:+#line 182 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 36:+#line 183 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 37:+#line 184 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 38:+#line 187 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 39:+#line 188 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 40:+#line 191 "../../src/foreign-dl-parser.y"+    {+                   igraph_i_dl_add_edge_w((yyvsp[(1) - (4)].integer)-1, (yyvsp[(2) - (4)].integer)-1, (yyvsp[(3) - (4)].real), context); }+    break;++  case 41:+#line 193 "../../src/foreign-dl-parser.y"+    {+		   igraph_i_dl_add_edge((yyvsp[(1) - (3)].integer)-1, (yyvsp[(2) - (3)].integer)-1, context);+}+    break;++  case 42:+#line 197 "../../src/foreign-dl-parser.y"+    { (yyval.integer)=igraph_pajek_get_number(igraph_dl_yyget_text(scanner), +					  igraph_dl_yyget_leng(scanner)); }+    break;++  case 43:+#line 200 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 44:+#line 201 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 45:+#line 204 "../../src/foreign-dl-parser.y"+    {+                          igraph_i_dl_add_edge_w((yyvsp[(1) - (4)].integer), (yyvsp[(2) - (4)].integer), (yyvsp[(3) - (4)].real), context); }+    break;++  case 46:+#line 206 "../../src/foreign-dl-parser.y"+    {+			  igraph_i_dl_add_edge((yyvsp[(1) - (3)].integer), (yyvsp[(2) - (3)].integer), context);+ }+    break;++  case 47:+#line 210 "../../src/foreign-dl-parser.y"+    { (yyval.real)=igraph_pajek_get_number(igraph_dl_yyget_text(scanner), +					 igraph_dl_yyget_leng(scanner)); }+    break;++  case 48:+#line 213 "../../src/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 229 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 50:+#line 231 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 51:+#line 232 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 52:+#line 233 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 53:+#line 234 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 54:+#line 235 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 55:+#line 238 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 56:+#line 239 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 57:+#line 242 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 58:+#line 244 "../../src/foreign-dl-parser.y"+    { context->from=igraph_pajek_get_number(igraph_dl_yyget_text(scanner),+							  igraph_dl_yyget_leng(scanner)); }+    break;++  case 59:+#line 247 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 60:+#line 247 "../../src/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 253 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 62:+#line 254 "../../src/foreign-dl-parser.y"+    {}+    break;++  case 63:+#line 257 "../../src/foreign-dl-parser.y"+    { }+    break;++  case 64:+#line 259 "../../src/foreign-dl-parser.y"+    {+  context->from=(yyvsp[(1) - (1)].integer);+ }+    break;++  case 66:+#line 263 "../../src/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 1884 "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 269 "../../src/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;+}+
+ igraph/src/foreign-gml-lexer.c view
@@ -0,0 +1,2055 @@+#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 10+#define YY_END_OF_BUFFER 11+/* 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,   11,    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 "../../src/foreign-gml-lexer.l"+/* +   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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 "../../src/foreign-gml-lexer.l"++/* +   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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 "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. */+#ifdef USING_R+#define fprintf(file, msg, ...) (1)+#endif+#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 514 "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 78 "../../src/foreign-gml-lexer.l"+++#line 759 "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 80 "../../src/foreign-gml-lexer.l"+{ /* comments ignored */ }+	YY_BREAK+case 2:+/* rule 2 can match eol */+YY_RULE_SETUP+#line 82 "../../src/foreign-gml-lexer.l"+{ return STRING; }+	YY_BREAK+case 3:+YY_RULE_SETUP+#line 83 "../../src/foreign-gml-lexer.l"+{ return NUM; }+	YY_BREAK+case 4:+YY_RULE_SETUP+#line 84 "../../src/foreign-gml-lexer.l"+{ return KEYWORD; }+	YY_BREAK+case 5:+YY_RULE_SETUP+#line 85 "../../src/foreign-gml-lexer.l"+{ return LISTOPEN; }+	YY_BREAK+case 6:+YY_RULE_SETUP+#line 86 "../../src/foreign-gml-lexer.l"+{ return LISTCLOSE; }+	YY_BREAK+case 7:+/* rule 7 can match eol */+YY_RULE_SETUP+#line 87 "../../src/foreign-gml-lexer.l"+{ }+	YY_BREAK+case 8:+/* rule 8 can match eol */+YY_RULE_SETUP+#line 88 "../../src/foreign-gml-lexer.l"+{ /* other whitespace ignored */ }+	YY_BREAK+case YY_STATE_EOF(INITIAL):+#line 90 "../../src/foreign-gml-lexer.l"+{ +                          if (yyextra->eof) {+			    yyterminate();+			  } else {+			    yyextra->eof=1;+			    return EOFF;+			  }			  +                        }+	YY_BREAK+case 9:+YY_RULE_SETUP+#line 98 "../../src/foreign-gml-lexer.l"+{ return ERROR; }+	YY_BREAK+case 10:+YY_RULE_SETUP+#line 99 "../../src/foreign-gml-lexer.l"+YY_FATAL_ERROR( "flex scanner jammed" );+	YY_BREAK+#line 912 "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 99 "../../src/foreign-gml-lexer.l"+++
+ igraph/src/foreign-gml-parser.c view
@@ -0,0 +1,1856 @@+/* 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,+     ERROR = 264+   };+#endif+/* Tokens.  */+#define STRING 258+#define NUM 259+#define KEYWORD 260+#define LISTOPEN 261+#define LISTCLOSE 262+#define EOFF 263+#define ERROR 264+++++/* Copy the first part of user declarations.  */+#line 23 "../../src/foreign-gml-parser.y"+++/* +   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@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 <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, +		       const 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 93 "../../src/foreign-gml-parser.y"+{+   struct {+      char *s;+      int len;+   } str;+   void *tree;+   double real;+}+/* Line 193 of yacc.c.  */+#line 192 "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 217 "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  10+/* 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   264++#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+};++#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[] =+{+      11,     0,    -1,    12,    -1,    12,     8,    -1,    13,    -1,+      12,    13,    -1,    14,    15,    -1,    14,    16,    -1,    14,+       6,    12,     7,    -1,    14,    14,    -1,     5,    -1,     4,+      -1,     3,    -1+};++/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */+static const yytype_uint8 yyrline[] =+{+       0,   121,   121,   122,   125,   126,   128,   130,   132,   134,+     138,   141,   144+};+#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", "ERROR", "$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,   264+};+# endif++/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */+static const yytype_uint8 yyr1[] =+{+       0,    10,    11,    11,    12,    12,    13,    13,    13,    13,+      14,    15,    16+};++/* 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,    11,    12,    13,    14,     0,     8,    13,     3,+       4,     6,    14,    15,    16,    12,     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 116 "../../src/foreign-gml-parser.y"+	{ igraph_Free((yyvaluep->str).s); };+#line 1121 "foreign-gml-parser.c"+	break;+      case 12: /* "list" */+#line 117 "../../src/foreign-gml-parser.y"+	{ igraph_gml_tree_destroy((yyvaluep->tree)); };+#line 1126 "foreign-gml-parser.c"+	break;+      case 13: /* "keyvalue" */+#line 117 "../../src/foreign-gml-parser.y"+	{ igraph_gml_tree_destroy((yyvaluep->tree)); };+#line 1131 "foreign-gml-parser.c"+	break;+      case 14: /* "key" */+#line 116 "../../src/foreign-gml-parser.y"+	{ igraph_Free((yyvaluep->str).s); };+#line 1136 "foreign-gml-parser.c"+	break;+      case 16: /* "string" */+#line 116 "../../src/foreign-gml-parser.y"+	{ igraph_Free((yyvaluep->str).s); };+#line 1141 "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 121 "../../src/foreign-gml-parser.y"+    { context->tree=(yyvsp[(1) - (1)].tree); }+    break;++  case 3:+#line 122 "../../src/foreign-gml-parser.y"+    { context->tree=(yyvsp[(1) - (2)].tree); }+    break;++  case 4:+#line 125 "../../src/foreign-gml-parser.y"+    { (yyval.tree)=(yyvsp[(1) - (1)].tree); }+    break;++  case 5:+#line 126 "../../src/foreign-gml-parser.y"+    { (yyval.tree)=igraph_i_gml_merge((yyvsp[(1) - (2)].tree), (yyvsp[(2) - (2)].tree)); }+    break;++  case 6:+#line 129 "../../src/foreign-gml-parser.y"+    { (yyval.tree)=igraph_i_gml_make_numeric((yyvsp[(1) - (2)].str).s, (yyvsp[(1) - (2)].str).len, (yyvsp[(2) - (2)].real)); }+    break;++  case 7:+#line 131 "../../src/foreign-gml-parser.y"+    { (yyval.tree)=igraph_i_gml_make_string((yyvsp[(1) - (2)].str).s, (yyvsp[(1) - (2)].str).len, (yyvsp[(2) - (2)].str).s, (yyvsp[(2) - (2)].str).len); }+    break;++  case 8:+#line 133 "../../src/foreign-gml-parser.y"+    { (yyval.tree)=igraph_i_gml_make_list((yyvsp[(1) - (4)].str).s, (yyvsp[(1) - (4)].str).len, (yyvsp[(3) - (4)].tree)); }+    break;++  case 9:+#line 135 "../../src/foreign-gml-parser.y"+    { (yyval.tree)=igraph_i_gml_make_numeric2((yyvsp[(1) - (2)].str).s, (yyvsp[(1) - (2)].str).len, (yyvsp[(2) - (2)].str).s, (yyvsp[(2) - (2)].str).len); }+    break;++  case 10:+#line 138 "../../src/foreign-gml-parser.y"+    { igraph_i_gml_get_keyword(igraph_gml_yyget_text(scanner), +					igraph_gml_yyget_leng(scanner), +					&(yyval.str)); USE((yyvsp[(1) - (1)].str)) }+    break;++  case 11:+#line 141 "../../src/foreign-gml-parser.y"+    { (yyval.real)=igraph_i_gml_get_real(igraph_gml_yyget_text(scanner), +				     igraph_gml_yyget_leng(scanner)); }+    break;++  case 12:+#line 144 "../../src/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 1525 "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 148 "../../src/foreign-gml-parser.y"+++int igraph_gml_yyerror(YYLTYPE* locp, igraph_i_gml_parsedata_t *context, +		       const 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;+}+
+ igraph/src/foreign-graphml.c view
@@ -0,0 +1,1846 @@+/* -*- mode: C -*-  */+/*+   IGraph R package.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include <locale.h>+#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 */++#define GRAPHML_NAMESPACE_URI "http://graphml.graphdrawing.org/xmlns"++#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_WITH_CODE(state, msg, code) do {  \+        if (state->successful) {                                    \+            igraph_error(msg, __FILE__, __LINE__, code);              \+            igraph_i_graphml_sax_handler_error(state, msg);           \+        }                                                           \+    } while (0)+#define GRAPHML_PARSE_ERROR(state, msg) \+    GRAPHML_PARSE_ERROR_WITH_CODE(state, msg, IGRAPH_PARSEERROR)+#define RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, msg, code) do {  \+        GRAPHML_PARSE_ERROR_WITH_CODE(state, msg, code);            \+        return;                                                     \+    } while (1)+#define RETURN_GRAPHML_PARSE_ERROR(state, msg) do {           \+        GRAPHML_PARSE_ERROR(state, msg);                            \+        return;                                                     \+    } while (1)++/* 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 */+    union {+        igraph_real_t as_numeric;+        igraph_bool_t as_boolean;+        char* as_string;+    } default_value;   /* Default value of the attribute, if any */+    igraph_attribute_record_t record;+} igraph_i_graphml_attribute_record_t;++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;+    igraph_i_graphml_attribute_record_t* current_attr_record;+    xmlChar *data_key;+    igraph_attribute_elemtype_t data_type;+    char *error_message;+    char *data_char;+    long int act_node;+    igraph_bool_t ignore_namespaces;+};++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_real_t igraph_i_graphml_parse_numeric(const char* char_data,+        igraph_real_t default_value) {+    double result;++    if (char_data == 0) {+        return default_value;+    }++    if (sscanf(char_data, "%lf", &result) == 0) {+        return default_value;+    }++    return result;+}++igraph_bool_t igraph_i_graphml_parse_boolean(const char* char_data,+        igraph_bool_t default_value) {+    int value;+    if (char_data == 0) {+        return default_value;+    }+    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 default_value;+    }+    return value != 0;+}++void igraph_i_graphml_attribute_record_destroy(igraph_i_graphml_attribute_record_t* rec) {+    if (rec->record.type == IGRAPH_ATTRIBUTE_NUMERIC) {+        if (rec->record.value != 0) {+            igraph_vector_destroy((igraph_vector_t*)rec->record.value);+            igraph_Free(rec->record.value);+        }+    } else if (rec->record.type == IGRAPH_ATTRIBUTE_STRING) {+        if (rec->record.value != 0) {+            igraph_strvector_destroy((igraph_strvector_t*)rec->record.value);+            if (rec->default_value.as_string != 0) {+                igraph_Free(rec->default_value.as_string);+            }+            igraph_Free(rec->record.value);+        }+    } else if (rec->record.type == IGRAPH_ATTRIBUTE_BOOLEAN) {+        if (rec->record.value != 0) {+            igraph_vector_bool_destroy((igraph_vector_bool_t*)rec->record.value);+            igraph_Free(rec->record.value);+        }+    }+    if (rec->id != 0) {+        igraph_Free(rec->id);+    }+    if (rec->record.name != 0) {+        igraph_Free(rec->record.name);+    }+}++void igraph_i_graphml_destroy_state(struct igraph_i_graphml_parser_state* state) {+    if (state->destroyed) {+        return;+    }+    state->destroyed = 1;++    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);+    }++    igraph_vector_ptr_destroy_all(&state->v_attrs);+    igraph_vector_ptr_destroy_all(&state->e_attrs);+    igraph_vector_ptr_destroy_all(&state->g_attrs);++    IGRAPH_FINALLY_CLEAN(1);+}++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;+    state->ignore_namespaces = 0;++    ret = igraph_vector_int_init(&state->prev_state_stack, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    ret = igraph_vector_int_reserve(&state->prev_state_stack, 32);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_FINALLY(igraph_vector_int_destroy, &state->prev_state_stack);++    ret = igraph_vector_ptr_init(&state->v_attrs, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&state->v_attrs,+                                          igraph_i_graphml_attribute_record_destroy);+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->v_attrs);++    ret = igraph_vector_ptr_init(&state->e_attrs, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&state->e_attrs,+                                          igraph_i_graphml_attribute_record_destroy);+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->e_attrs);++    ret = igraph_vector_ptr_init(&state->g_attrs, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&state->g_attrs,+                                          igraph_i_graphml_attribute_record_destroy);+    IGRAPH_FINALLY(igraph_vector_ptr_destroy, &state->g_attrs);++    ret = igraph_vector_init(&state->edgelist, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_FINALLY(igraph_vector_destroy, &state->edgelist);++    ret = igraph_trie_init(&state->node_trie, 1);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_FINALLY(igraph_trie_destroy, &state->node_trie);++    ret = igraph_strvector_init(&state->edgeids, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_FINALLY(igraph_strvector_destroy, &state->edgeids);++    ret = igraph_trie_init(&state->v_names, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_FINALLY(igraph_trie_destroy, &state->v_names);++    ret = igraph_trie_init(&state->e_names, 0);+    if (ret) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+    }+    IGRAPH_FINALLY(igraph_trie_destroy, &state->e_names);++    ret = igraph_trie_init(&state->g_names, 0);+    if (ret) {+        RETURN_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] = graphmlrec->default_value.as_numeric;+                }+            } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+                igraph_strvector_t *strvec = (igraph_strvector_t*)rec->value;+                long int origsize = igraph_strvector_size(strvec);+                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, graphmlrec->default_value.as_string);+                }+            } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {+                igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value;+                long int origsize = igraph_vector_bool_size(boolvec);+                long int nodes = igraph_trie_size(&state->node_trie);+                igraph_vector_bool_resize(boolvec, nodes);+                for (l = origsize; l < nodes; l++) {+                    VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean;+                }+            }+            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);+        }++        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] = graphmlrec->default_value.as_numeric;+                }+            } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+                igraph_strvector_t *strvec = (igraph_strvector_t*)rec->value;+                long int origsize = igraph_strvector_size(strvec);+                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, graphmlrec->default_value.as_string);+                }+            } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {+                igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value;+                long int origsize = igraph_vector_bool_size(boolvec);+                long int edges = igraph_vector_size(&state->edgelist) / 2;+                igraph_vector_bool_resize(boolvec, edges);+                for (l = origsize; l < edges; l++) {+                    VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean;+                }+            }+            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] = graphmlrec->default_value.as_numeric;+                }+            } else if (rec->type == IGRAPH_ATTRIBUTE_STRING) {+                igraph_strvector_t *strvec = (igraph_strvector_t*)rec->value;+                long int origsize = igraph_strvector_size(strvec);+                igraph_strvector_resize(strvec, 1);+                for (l = origsize; l < 1; l++) {+                    igraph_strvector_set(strvec, l, graphmlrec->default_value.as_string);+                }+            } else if (rec->type == IGRAPH_ATTRIBUTE_BOOLEAN) {+                igraph_vector_bool_t *boolvec = (igraph_vector_bool_t*)rec->value;+                long int origsize = igraph_vector_bool_size(boolvec);+                igraph_vector_bool_resize(boolvec, 1);+                for (l = origsize; l < 1; l++) {+                    VECTOR(*boolvec)[l] = graphmlrec->default_value.as_boolean;+                }+            }+            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... */++#define XML_ATTR_LOCALNAME(it) (*(it))+#define XML_ATTR_PREFIX(it) (*(it+1))+#define XML_ATTR_URI(it) (*(it+2))+#define XML_ATTR_VALUE_START(it) (*(it+3))+#define XML_ATTR_VALUE_END(it) (*(it+4))+#define XML_ATTR_VALUE(it) *(it+3), (*(it+4))-(*(it+3))++igraph_i_graphml_attribute_record_t* igraph_i_graphml_add_attribute_key(+    const xmlChar** attrs, int nb_attrs,+    struct igraph_i_graphml_parser_state *state) {+    xmlChar **it;+    xmlChar *localname;+    igraph_trie_t *trie = 0;+    igraph_vector_ptr_t *ptrvector = 0;+    long int id;+    unsigned short int skip = 0;+    int i, ret;+    igraph_i_graphml_attribute_record_t *rec;++    if (!state->successful) {+        return 0;+    }++    rec = igraph_Calloc(1, igraph_i_graphml_attribute_record_t);+    if (rec == 0) {+        GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);+        return 0;+    }+    IGRAPH_FINALLY(igraph_free, rec);++    rec->type = I_GRAPHML_UNKNOWN_TYPE;++    for (i = 0, it = (xmlChar**)attrs; i < nb_attrs; i++, it += 5) {+        if (XML_ATTR_URI(it) != 0 &&+            !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {+            continue;+        }++        localname = XML_ATTR_LOCALNAME(it);++        if (xmlStrEqual(localname, toXmlChar("id"))) {+            rec->id = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));+        } else if (xmlStrEqual(localname, toXmlChar("attr.name"))) {+            rec->record.name = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));+        } else if (xmlStrEqual(localname, toXmlChar("attr.type"))) {+            if (!xmlStrncmp(toXmlChar("boolean"), XML_ATTR_VALUE(it))) {+                rec->type = I_GRAPHML_BOOLEAN;+                rec->record.type = IGRAPH_ATTRIBUTE_BOOLEAN;+                rec->default_value.as_boolean = 0;+            } else if (!xmlStrncmp(toXmlChar("string"), XML_ATTR_VALUE(it))) {+                rec->type = I_GRAPHML_STRING;+                rec->record.type = IGRAPH_ATTRIBUTE_STRING;+                rec->default_value.as_string = strdup("");+            } else if (!xmlStrncmp(toXmlChar("float"), XML_ATTR_VALUE(it))) {+                rec->type = I_GRAPHML_FLOAT;+                rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC;+                rec->default_value.as_numeric = IGRAPH_NAN;+            } else if (!xmlStrncmp(toXmlChar("double"), XML_ATTR_VALUE(it))) {+                rec->type = I_GRAPHML_DOUBLE;+                rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC;+                rec->default_value.as_numeric = IGRAPH_NAN;+            } else if (!xmlStrncmp(toXmlChar("int"), XML_ATTR_VALUE(it))) {+                rec->type = I_GRAPHML_INTEGER;+                rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC;+                rec->default_value.as_numeric = IGRAPH_NAN;+            } else if (!xmlStrncmp(toXmlChar("long"), XML_ATTR_VALUE(it))) {+                rec->type = I_GRAPHML_LONG;+                rec->record.type = IGRAPH_ATTRIBUTE_NUMERIC;+                rec->default_value.as_numeric = IGRAPH_NAN;+            } else {+                GRAPHML_PARSE_ERROR(state,+                                    "Cannot parse GraphML file, unknown attribute type");+                return 0;+            }+        } else if (xmlStrEqual(*it, toXmlChar("for"))) {+            /* graph, vertex or edge attribute? */+            if (!xmlStrncmp(toXmlChar("graph"), XML_ATTR_VALUE(it))) {+                trie = &state->g_names;+                ptrvector = &state->g_attrs;+            } else if (!xmlStrncmp(toXmlChar("node"), XML_ATTR_VALUE(it))) {+                trie = &state->v_names;+                ptrvector = &state->v_attrs;+            } else if (!xmlStrncmp(toXmlChar("edge"), XML_ATTR_VALUE(it))) {+                trie = &state->e_names;+                ptrvector = &state->e_attrs;+            } else if (!xmlStrncmp(toXmlChar("graphml"), XML_ATTR_VALUE(it))) {+                igraph_i_report_unhandled_attribute_target("graphml", __FILE__, __LINE__);+                skip = 1;+            } else if (!xmlStrncmp(toXmlChar("hyperedge"), XML_ATTR_VALUE(it))) {+                igraph_i_report_unhandled_attribute_target("hyperedge", __FILE__, __LINE__);+                skip = 1;+            } else if (!xmlStrncmp(toXmlChar("port"), XML_ATTR_VALUE(it))) {+                igraph_i_report_unhandled_attribute_target("port", __FILE__, __LINE__);+                skip = 1;+            } else if (!xmlStrncmp(toXmlChar("endpoint"), XML_ATTR_VALUE(it))) {+                igraph_i_report_unhandled_attribute_target("endpoint", __FILE__, __LINE__);+                skip = 1;+            } else if (!xmlStrncmp(toXmlChar("all"), XML_ATTR_VALUE(it))) {+                /* TODO: we should handle this */+                igraph_i_report_unhandled_attribute_target("all", __FILE__, __LINE__);+                skip = 1;+            } else {+                GRAPHML_PARSE_ERROR(state,+                                    "Cannot parse GraphML file, unknown value in the 'for' attribute of a <key> tag");+                return 0;+            }+        }+    }++    /* 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");+        return 0;+    }++    /* 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");+        return 0;+    }++    /* if the code above requested skipping the attribute, free everything and+     * return */+    if (skip) {+        igraph_free(rec);+        IGRAPH_FINALLY_CLEAN(1);+        return 0;+    }++    /* add to trie, attribues */+    igraph_trie_get(trie, rec->id, &id);+    if (id != igraph_trie_size(trie) - 1) {+        GRAPHML_PARSE_ERROR(state, "Cannot parse GraphML file, duplicate attribute");+        return 0;+    }++    ret = igraph_vector_ptr_push_back(ptrvector, rec);+    if (ret) {+        GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot read GraphML file", ret);+        return 0;+    }++    /* Ownership of 'rec' is now taken by ptrvector so we can clean the+     * 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);+            return 0;+        }+        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);+            return 0;+        }+        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);+            return 0;+        }+        rec->record.value = strvec;+        igraph_strvector_init(strvec, 0);+        break;+    default: break;+    }++    return rec;+}++void igraph_i_graphml_attribute_data_setup(struct igraph_i_graphml_parser_state *state,+        const xmlChar **attrs,+        int nb_attrs,+        igraph_attribute_elemtype_t type) {+    xmlChar **it;+    int i;++    if (!state->successful) {+        return;+    }++    for (i = 0, it = (xmlChar**)attrs; i < nb_attrs; i++, it += 5) {+        if (XML_ATTR_URI(it) != 0 &&+            !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {+            continue;+        }++        if (xmlStrEqual(*it, toXmlChar("key"))) {+            if (state->data_key) {+                free(state->data_key);+            }+            state->data_key = xmlStrndup(XML_ATTR_VALUE(it));+            if (state->data_char) {+                free(state->data_char);+            }+            state->data_char = 0;+            state->data_type = type;+        } else {+            /* ignore */+        }+    }+}++void igraph_i_graphml_append_to_data_char(struct igraph_i_graphml_parser_state *state,+        const xmlChar *data, int len) {+    long int data_char_new_start = 0;++    if (!state->successful) {+        return;+    }++    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) {+        RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", IGRAPH_ENOMEM);+    }+    memcpy(state->data_char + data_char_new_start, data,+           (size_t) len * sizeof(xmlChar));+    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 = state->act_node;+        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;+    }++    if (key == 0) {+        /* no key specified, issue a warning */+        igraph_warningf(+            "missing attribute key in a <data> tag, ignoring attribute",+            __FILE__, __LINE__, 0,+            key+        );+        igraph_Free(state->data_char);+        return;+    }++    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;+        long int s, i;+        const char* strvalue;+    case IGRAPH_ATTRIBUTE_BOOLEAN:+        boolvec = (igraph_vector_bool_t *)rec->value;+        s = igraph_vector_bool_size(boolvec);+        if (id >= s) {+            ret = igraph_vector_bool_resize(boolvec, id + 1);+            if (ret) {+                RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+            }+            for (i = s; i < id; i++) {+                VECTOR(*boolvec)[i] = graphmlrec->default_value.as_boolean;+            }+        }+        VECTOR(*boolvec)[id] = igraph_i_graphml_parse_boolean(state->data_char,+                               graphmlrec->default_value.as_boolean);+        break;+    case IGRAPH_ATTRIBUTE_NUMERIC:+        vec = (igraph_vector_t *)rec->value;+        s = igraph_vector_size(vec);+        if (id >= s) {+            ret = igraph_vector_resize(vec, id + 1);+            if (ret) {+                RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+            }+            for (i = s; i < id; i++) {+                VECTOR(*vec)[i] = graphmlrec->default_value.as_numeric;+            }+        }+        VECTOR(*vec)[id] = igraph_i_graphml_parse_numeric(state->data_char,+                           graphmlrec->default_value.as_numeric);+        break;+    case IGRAPH_ATTRIBUTE_STRING:+        strvec = (igraph_strvector_t *)rec->value;+        s = igraph_strvector_size(strvec);+        if (id >= s) {+            ret = igraph_strvector_resize(strvec, id + 1);+            if (ret) {+                RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+            }+            strvalue = graphmlrec->default_value.as_string;+            for (i = s; i < id; i++) {+                igraph_strvector_set(strvec, i, strvalue);+            }+        }+        if (state->data_char) {+            strvalue = state->data_char;+        } else {+            strvalue = graphmlrec->default_value.as_string;+        }+        ret = igraph_strvector_set(strvec, id, strvalue);+        if (ret) {+            RETURN_GRAPHML_PARSE_ERROR_WITH_CODE(state, "Cannot parse GraphML file", ret);+        }+        break;+    default:+        break;+    }++    if (state->data_char) {+        igraph_Free(state->data_char);+    }+}++void igraph_i_graphml_attribute_default_value_finish(+    struct igraph_i_graphml_parser_state *state) {+    igraph_i_graphml_attribute_record_t *graphmlrec = state->current_attr_record;++    if (graphmlrec == 0) {+        igraph_warning("state->current_attr_record was null where it should have been "+                       "non-null; this is probably a bug. Please notify the developers!",+                       __FILE__, __LINE__, 0);+        return;+    }++    if (state->data_char == 0) {+        return;+    }++    switch (graphmlrec->record.type) {+    case IGRAPH_ATTRIBUTE_BOOLEAN:+        graphmlrec->default_value.as_boolean = igraph_i_graphml_parse_boolean(+                state->data_char, 0);+        break;+    case IGRAPH_ATTRIBUTE_NUMERIC:+        graphmlrec->default_value.as_numeric = igraph_i_graphml_parse_numeric(+                state->data_char, IGRAPH_NAN);+        break;+    case IGRAPH_ATTRIBUTE_STRING:+        if (state->data_char) {+            if (graphmlrec->default_value.as_string != 0) {+                free(graphmlrec->default_value.as_string);+            }+            graphmlrec->default_value.as_string = strdup(state->data_char);+        }+        break;+    default:+        break;+    }++    if (state->data_char) {+        igraph_Free(state->data_char);+    }+}++void igraph_i_graphml_sax_handler_start_element_ns(+    void *state0, const xmlChar* localname, const xmlChar* prefix,+    const xmlChar* uri, int nb_namespaces, const xmlChar** namespaces,+    int nb_attributes, int nb_defaulted, const xmlChar** attributes) {+    struct igraph_i_graphml_parser_state *state =+        (struct igraph_i_graphml_parser_state*)state0;+    xmlChar** it;+    char* attr_value;+    long int id1, id2;+    int i;+    igraph_bool_t tag_is_unknown = 0;++    if (!state->successful) {+        return;+    }++    if (uri) {+        if (!xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), uri)) {+            /* Tag is in a different namespace, so treat it as an unknown start+             * tag irrespectively of our state */+            tag_is_unknown = 1;+        }+    } else {+        /* No namespace URI. If we are in lenient mode, accept it and proceed+         * as if we are in the GraphML namespace to handle lots of naive+         * non-namespace-aware GraphML files floating out there. If we are not+         * in lenient mode _but_ we are in the START state, accept it as well+         * and see whether the root tag is <graphml> (in which case we will+         * enter lenient mode). Otherwise, reject the tag */+        if (!state->ignore_namespaces && state->st != START) {+            tag_is_unknown = 1;+        }+    }++    if (tag_is_unknown) {+        igraph_i_graphml_handle_unknown_start_tag(state);+        return;+    }++    switch (state->st) {+    case START:+        /* If we are in the START state and received a graphml tag,+         * change to INSIDE_GRAPHML state. Otherwise, change to UNKNOWN. */+        if (xmlStrEqual(localname, toXmlChar("graphml"))) {+            if (uri == 0) {+                state->ignore_namespaces = 1;+            }+            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(localname, toXmlChar("graph"))) {+            if (state->index == 0) {+                state->st = INSIDE_GRAPH;+                for (i = 0, it = (xmlChar**)attributes; i < nb_attributes; i++, it += 5) {+                    if (XML_ATTR_URI(it) != 0 &&+                        !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {+                        /* Attribute is from a different namespace, so skip it */+                        continue;+                    }+                    if (xmlStrEqual(*it, toXmlChar("edgedefault"))) {+                        if (!xmlStrncmp(toXmlChar("directed"), XML_ATTR_VALUE(it))) {+                            state->edges_directed = 1;+                        } else if (!xmlStrncmp(toXmlChar("undirected"), XML_ATTR_VALUE(it))) {+                            state->edges_directed = 0;+                        }+                    }+                }+            }+            state->index--;+        } else if (xmlStrEqual(localname, toXmlChar("key"))) {+            state->current_attr_record =+                igraph_i_graphml_add_attribute_key(attributes, nb_attributes, 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(localname, 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(localname, toXmlChar("edge"))) {+            id1 = -1; id2 = -1;+            for (i = 0, it = (xmlChar**)attributes; i < nb_attributes; i++, it += 5) {+                if (XML_ATTR_URI(it) != 0 &&+                    !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {+                    /* Attribute is from a different namespace, so skip it */+                    continue;+                }+                if (xmlStrEqual(*it, toXmlChar("source"))) {+                    attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));+                    igraph_trie_get(&state->node_trie, attr_value, &id1);+                    free(attr_value);+                } else if (xmlStrEqual(*it, toXmlChar("target"))) {+                    attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));+                    igraph_trie_get(&state->node_trie, attr_value, &id2);+                    free(attr_value);+                } else if (xmlStrEqual(*it, toXmlChar("id"))) {+                    long int edges = igraph_vector_size(&state->edgelist) / 2 + 1;+                    long int origsize = igraph_strvector_size(&state->edgeids);+                    attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));+                    igraph_strvector_resize(&state->edgeids, edges);+                    for (; origsize < edges - 1; origsize++) {+                        igraph_strvector_set(&state->edgeids, origsize, "");+                    }+                    igraph_strvector_set(&state->edgeids, edges - 1, attr_value);+                    free(attr_value);+                }+            }+            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(localname, toXmlChar("node"))) {+            id1 = -1;+            for (i = 0, it = (xmlChar**)attributes; i < nb_attributes; i++, it += 5) {+                if (XML_ATTR_URI(it) != 0 &&+                    !xmlStrEqual(toXmlChar(GRAPHML_NAMESPACE_URI), XML_ATTR_URI(it))) {+                    /* Attribute is from a different namespace, so skip it */+                    continue;+                }+                if (xmlStrEqual(XML_ATTR_LOCALNAME(it), toXmlChar("id"))) {+                    attr_value = fromXmlChar(xmlStrndup(XML_ATTR_VALUE(it)));+                    igraph_trie_get(&state->node_trie, attr_value, &id1);+                    free(attr_value);+                    break;+                }+            }+            if (id1 >= 0) {+                state->act_node = id1;+            } else {+                state->act_node = -1;+                igraph_i_graphml_sax_handler_error(state, "Node with missing id encountered");+                return;+            }+            state->st = INSIDE_NODE;+        } else if (xmlStrEqual(localname, toXmlChar("data"))) {+            igraph_i_graphml_attribute_data_setup(state, attributes, nb_attributes,+                                                  IGRAPH_ATTRIBUTE_GRAPH);+            igraph_vector_int_push_back(&state->prev_state_stack, state->st);+            state->st = INSIDE_DATA;+        } else {+            igraph_i_graphml_handle_unknown_start_tag(state);+        }+        break;++    case INSIDE_NODE:+        if (xmlStrEqual(localname, toXmlChar("data"))) {+            igraph_i_graphml_attribute_data_setup(state, attributes, nb_attributes,+                                                  IGRAPH_ATTRIBUTE_VERTEX);+            igraph_vector_int_push_back(&state->prev_state_stack, state->st);+            state->st = INSIDE_DATA;+        }+        break;++    case INSIDE_EDGE:+        if (xmlStrEqual(localname, toXmlChar("data"))) {+            igraph_i_graphml_attribute_data_setup(state, attributes, nb_attributes,+                                                  IGRAPH_ATTRIBUTE_EDGE);+            igraph_vector_int_push_back(&state->prev_state_stack, state->st);+            state->st = INSIDE_DATA;+        }+        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_ns(void *state0,+        const xmlChar* localname, const xmlChar* prefix,+        const xmlChar* uri) {+    struct igraph_i_graphml_parser_state *state =+        (struct igraph_i_graphml_parser_state*)state0;++    if (!state->successful) {+        return;+    }++    IGRAPH_UNUSED(localname);+    IGRAPH_UNUSED(prefix);+    IGRAPH_UNUSED(uri);++    switch (state->st) {+    case INSIDE_GRAPHML:+        state->st = FINISH;+        break;++    case INSIDE_GRAPH:+        state->st = INSIDE_GRAPHML;+        break;++    case INSIDE_KEY:+        state->current_attr_record = 0;+        state->st = INSIDE_GRAPHML;+        break;++    case INSIDE_DEFAULT:+        igraph_i_graphml_attribute_default_value_finish(state);+        state->st = INSIDE_KEY;+        break;++    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:+        break;++    case INSIDE_DATA:+    case INSIDE_DEFAULT:+        igraph_i_graphml_append_to_data_char(state, ch, len);+        break;++    default:+        /* just ignore it */+        break;+    }+}++static xmlSAXHandler igraph_i_graphml_sax_handler = {+    /* internalSubset = */ 0,+    /* isStandalone = */ 0,+    /* hasInternalSubset = */ 0,+    /* hasExternalSubset = */ 0,+    /* resolveEntity = */ 0,+    /* getEntity = */ igraph_i_graphml_sax_handler_get_entity,+    /* entityDecl = */ 0,+    /* notationDecl = */ 0,+    /* attributeDecl = */ 0,+    /* elementDecl = */ 0,+    /* unparsedEntityDecl = */ 0,+    /* setDocumentLocator = */ 0,+    /* startDocument = */ igraph_i_graphml_sax_handler_start_document,+    /* endDocument = */ igraph_i_graphml_sax_handler_end_document,+    /* startElement = */ 0,+    /* endElement = */ 0,+    /* reference = */ 0,+    /* characters = */ igraph_i_graphml_sax_handler_chars,+    /* ignorableWhitespaceFunc = */ 0,+    /* processingInstruction = */ 0,+    /* comment = */ 0,+    /* warning = */ igraph_i_graphml_sax_handler_error,+    /* error = */ igraph_i_graphml_sax_handler_error,+    /* fatalError = */ igraph_i_graphml_sax_handler_error,+    /* getParameterEntity = */ 0,+    /* cdataBlock = */ 0,+    /* externalSubset = */ 0,+    /* initialized = */ XML_SAX2_MAGIC,+    /* _private = */ 0,+    /* startElementNs = */ igraph_i_graphml_sax_handler_start_element_ns,+    /* endElementNs = */ igraph_i_graphml_sax_handler_end_element_ns,+    /* serror = */ 0+};++#endif++#define IS_FORBIDDEN_CONTROL_CHAR(x) ((x) < ' ' && (x) != '\t' && (x) != '\r' && (x) != '\n')++int igraph_i_xml_escape(char* src, char** dest) {+    long int destlen = 0;+    char *s, *d;+    unsigned char ch;++    for (s = src; *s; s++, destlen++) {+        ch = (unsigned char)(*s);+        if (ch == '&') {+            destlen += 4;+        } else if (ch == '<') {+            destlen += 3;+        } else if (ch == '>') {+            destlen += 3;+        } else if (ch == '"') {+            destlen += 5;+        } else if (ch == '\'') {+            destlen += 5;+        } else if (IS_FORBIDDEN_CONTROL_CHAR(ch)) {+            char msg[4096];+            snprintf(msg, 4096, "Forbidden control character 0x%02X found in igraph_i_xml_escape",+                     ch);+            IGRAPH_ERROR(msg, IGRAPH_EINVAL);+        }+    }+    *dest = igraph_Calloc(destlen + 1, char);+    if (!*dest) {+        IGRAPH_ERROR("Not enough memory", IGRAPH_ENOMEM);+    }+    for (s = src, d = *dest; *s; s++, d++) {+        ch = (unsigned char)(*s);+        switch (ch) {+        case '&':+            strcpy(d, "&amp;"); d += 4; break;+        case '<':+            strcpy(d, "&lt;"); d += 3; break;+        case '>':+            strcpy(d, "&gt;"); d += 3; break;+        case '"':+            strcpy(d, "&quot;"); d += 5; break;+        case '\'':+            strcpy(d, "&apos;"); d += 5; break;+        default:+            *d = ch;+        }+    }+    *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);+    }++    /* Set parsing options */+    if (xmlCtxtUseOptions(ctxt,+                          XML_PARSE_NOENT | XML_PARSE_NOBLANKS |+                          XML_PARSE_NONET | XML_PARSE_NSCLEAN |+                          XML_PARSE_NOCDATA | XML_PARSE_HUGE+                         )) {+        IGRAPH_ERROR("Cannot set options for the parser context", IGRAPH_EINVAL);+    }++    /* Parse the file */+    while ((res = (int) fread(buffer, 1, 4096, instream)) > 0) {+        xmlParseChunk(ctxt, buffer, res, 0);+        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_" : "";++    /* set standard C locale lest we sometimes get commas instead of dots */+    char *saved_locale = strdup(setlocale(LC_NUMERIC, NULL));+    if (saved_locale == NULL) {+        IGRAPH_ERROR("Not enough memory", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, saved_locale);+    setlocale(LC_NUMERIC, "C");++    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=\"%s\"\n", GRAPHML_NAMESPACE_URI);+    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=\"%s\n", GRAPHML_NAMESPACE_URI);+    if (ret < 0) {+        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+    }+    ret = fprintf(outstream, "         %s/1.0/graphml.xsd\">\n", GRAPHML_NAMESPACE_URI);+    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\">", gprefix, name_escaped);+                igraph_Free(name_escaped);+                if (ret < 0) {+                    IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                }+                ret = igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);+                if (ret < 0) {+                    IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                }+                ret = fprintf(outstream, "</data>\n");+                if (ret < 0) {+                    IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                }+            }+        } else if (VECTOR(gtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {+            char *s, *s_escaped;+            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\">", vprefix, name_escaped);+                    igraph_Free(name_escaped);+                    if (ret < 0) {+                        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                    }+                    ret = igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);+                    if (ret < 0) {+                        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                    }+                    ret = fprintf(outstream, "</data>\n");+                    if (ret < 0) {+                        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                    }+                }+            } else if (VECTOR(vtypes)[i] == IGRAPH_ATTRIBUTE_STRING) {+                char *s, *s_escaped;+                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\">", eprefix, name_escaped);+                    igraph_Free(name_escaped);+                    if (ret < 0) {+                        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                    }+                    ret = igraph_real_fprintf_precise(outstream, VECTOR(numv)[0]);+                    if (ret < 0) {+                        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                    }+                    ret = fprintf(outstream, "</data>\n");+                    if (ret < 0) {+                        IGRAPH_ERROR("Write failed", IGRAPH_EFILE);+                    }+                }+            } else if (VECTOR(etypes)[i] == IGRAPH_ATTRIBUTE_STRING) {+                char *s, *s_escaped;+                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);+    }++    /* reset locale to whatever was before this function */+    setlocale(LC_NUMERIC, saved_locale);++    igraph_free(saved_locale);+    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(10);++    return 0;+}
+ igraph/src/foreign-lgl-lexer.c view
@@ -0,0 +1,2014 @@+#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 6+#define YY_END_OF_BUFFER 7+/* 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,    7,    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 "../../src/foreign-lgl-lexer.l"+/* +   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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 "../../src/foreign-lgl-lexer.l"++/* +   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@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 "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. */+#ifdef USING_R+#define fprintf(file, msg, ...) (1)+#endif+#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 500 "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 77 "../../src/foreign-lgl-lexer.l"+++ /* --------------------------------------------------hashmark------*/+#line 743 "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 80 "../../src/foreign-lgl-lexer.l"+{ return HASH; }+	YY_BREAK+/* ------------------------------------------------whitespace------*/+case 2:+YY_RULE_SETUP+#line 83 "../../src/foreign-lgl-lexer.l"+{ }+	YY_BREAK+/* ---------------------------------------------------newline------*/+case 3:+/* rule 3 can match eol */+YY_RULE_SETUP+#line 86 "../../src/foreign-lgl-lexer.l"+{ return NEWLINE; }+	YY_BREAK+/* ----------------------------------------------alphanumeric------*/+case 4:+YY_RULE_SETUP+#line 89 "../../src/foreign-lgl-lexer.l"+{ return ALNUM; }+	YY_BREAK+case YY_STATE_EOF(INITIAL):+#line 91 "../../src/foreign-lgl-lexer.l"+{ if (yyextra->eof) {+                       yyterminate();+                    } else {+                       yyextra->eof=1;+                       return NEWLINE; +                    }+                  }+	YY_BREAK+case 5:+YY_RULE_SETUP+#line 99 "../../src/foreign-lgl-lexer.l"+{ return ERROR; }+	YY_BREAK+case 6:+YY_RULE_SETUP+#line 101 "../../src/foreign-lgl-lexer.l"+YY_FATAL_ERROR( "flex scanner jammed" );+	YY_BREAK+#line 874 "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 101 "../../src/foreign-lgl-lexer.l"+++
+ igraph/src/foreign-lgl-parser.c view
@@ -0,0 +1,1696 @@+/* 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,+     ERROR = 261+   };+#endif+/* Tokens.  */+#define ALNUM 258+#define NEWLINE 259+#define HASH 260+#define ERROR 261+++++/* Copy the first part of user declarations.  */+#line 23 "../../src/foreign-lgl-parser.y"+++/* +   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@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 <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, +		       const 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 81 "../../src/foreign-lgl-parser.y"+{+  long int edgenum;+  double weightnum;+}+/* Line 193 of yacc.c.  */+#line 170 "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 195 "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  7+/* 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   261++#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+};++#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[] =+{+       8,     0,    -1,    -1,     8,     4,    -1,     8,     9,    -1,+      10,    11,    -1,     5,    13,     4,    -1,    -1,    11,    12,+      -1,    13,     4,    -1,    13,    14,     4,    -1,     3,    -1,+       3,    -1+};++/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */+static const yytype_uint8 yyrline[] =+{+       0,    96,    96,    97,    98,   101,   103,   105,   105,   107,+     112,   121,   126+};+#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", "ERROR",+  "$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,   261+};+# endif++/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */+static const yytype_uint8 yyr1[] =+{+       0,     7,     8,     8,     8,     9,    10,    11,    11,    12,+      12,    13,    14+};++/* 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,     8,     0,     4,     5,     9,    10,     3,    13,    11,+       4,    12,    13,     3,     4,    14,     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 103 "../../src/foreign-lgl-parser.y"+    { context->actvertex=(yyvsp[(2) - (3)].edgenum); }+    break;++  case 9:+#line 107 "../../src/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 112 "../../src/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 121 "../../src/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 126 "../../src/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 1456 "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 129 "../../src/foreign-lgl-parser.y"+++int igraph_lgl_yyerror(YYLTYPE* locp, igraph_i_lgl_parsedata_t *context, +		       const 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;+} +
+ igraph/src/foreign-ncol-lexer.c view
@@ -0,0 +1,2010 @@+#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 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[12] =+    {   0,+        1,    1,    6,    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 "../../src/foreign-ncol-lexer.l"+/* +   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@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 "../../src/foreign-ncol-lexer.l"++/* +   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@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 "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. */+#ifdef USING_R+#define fprintf(file, msg, ...) (1)+#endif+#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 500 "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 77 "../../src/foreign-ncol-lexer.l"+++ /* ------------------------------------------------whitespace------*/+#line 743 "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 80 "../../src/foreign-ncol-lexer.l"+{ }+	YY_BREAK+/* ---------------------------------------------------newline------*/+case 2:+/* rule 2 can match eol */+YY_RULE_SETUP+#line 83 "../../src/foreign-ncol-lexer.l"+{ return NEWLINE; }+	YY_BREAK+/* ----------------------------------------------alphanumeric------*/+case 3:+YY_RULE_SETUP+#line 86 "../../src/foreign-ncol-lexer.l"+{ return ALNUM; }+	YY_BREAK+case YY_STATE_EOF(INITIAL):+#line 88 "../../src/foreign-ncol-lexer.l"+{ if (yyextra->eof) {+                       yyterminate();+                    } else {+                       yyextra->eof=1;+                       return NEWLINE; +                    }+                  }+	YY_BREAK+/* ---------------------------------------------anything else------*/+case 4:+YY_RULE_SETUP+#line 97 "../../src/foreign-ncol-lexer.l"+{ return ERROR; }+	YY_BREAK+case 5:+YY_RULE_SETUP+#line 99 "../../src/foreign-ncol-lexer.l"+YY_FATAL_ERROR( "flex scanner jammed" );+	YY_BREAK+#line 869 "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 "../../src/foreign-ncol-lexer.l"++++
+ igraph/src/foreign-ncol-parser.c view
@@ -0,0 +1,1685 @@+/* 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,+     ERROR = 260+   };+#endif+/* Tokens.  */+#define ALNUM 258+#define NEWLINE 259+#define ERROR 260+++++/* Copy the first part of user declarations.  */+#line 23 "../../src/foreign-ncol-parser.y"+++/* +   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@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 <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 82 "../../src/foreign-ncol-parser.y"+{+  long int edgenum;+  double weightnum;+}+/* Line 193 of yacc.c.  */+#line 169 "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 194 "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  6+/* 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   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,    14,    19,    21+};++/* 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,     9,     4,    -1,     9,     9,    10,     4,    -1,     3,+      -1,     3,    -1+};++/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */+static const yytype_uint8 yyrline[] =+{+       0,    96,    96,    97,    98,   101,   106,   114,   119+};+#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", "ERROR", "$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,   260+};+# endif++/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */+static const yytype_uint8 yyr1[] =+{+       0,     6,     7,     7,     7,     8,     8,     9,    10+};++/* 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,     7,     0,     3,     4,     8,     9,     9,     3,     4,+      10,     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 101 "../../src/foreign-ncol-parser.y"+    { +           igraph_vector_push_back(context->vector, (yyvsp[(1) - (3)].edgenum));+           igraph_vector_push_back(context->vector, (yyvsp[(2) - (3)].edgenum));+           igraph_vector_push_back(context->weights, 0);+       }+    break;++  case 6:+#line 106 "../../src/foreign-ncol-parser.y"+    { +           igraph_vector_push_back(context->vector, (yyvsp[(1) - (4)].edgenum));+           igraph_vector_push_back(context->vector, (yyvsp[(2) - (4)].edgenum));+           igraph_vector_push_back(context->weights, (yyvsp[(3) - (4)].weightnum));+	   context->has_weights = 1;+       }+    break;++  case 7:+#line 114 "../../src/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 119 "../../src/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 1444 "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 122 "../../src/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;+} +
+ igraph/src/foreign-pajek-lexer.c view
@@ -0,0 +1,2470 @@+#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 48+#define YY_END_OF_BUFFER 49+/* 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,   49,   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 "../../src/foreign-pajek-lexer.l"+/* +   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@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 "../../src/foreign-pajek-lexer.l"++/* +   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@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 "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. */+#ifdef USING_R+#define fprintf(file, msg, ...) (1)+#endif+#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 619 "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 78 "../../src/foreign-pajek-lexer.l"+++#line 861 "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 80 "../../src/foreign-pajek-lexer.l"+{ }+	YY_BREAK+case 2:+/* rule 2 can match eol */+YY_RULE_SETUP+#line 81 "../../src/foreign-pajek-lexer.l"+{ }+	YY_BREAK+case 3:+/* rule 3 can match eol */+YY_RULE_SETUP+#line 82 "../../src/foreign-pajek-lexer.l"+{ }+	YY_BREAK+case 4:+YY_RULE_SETUP+#line 83 "../../src/foreign-pajek-lexer.l"+{ return NETWORKLINE; }+	YY_BREAK+case 5:+YY_RULE_SETUP+#line 84 "../../src/foreign-pajek-lexer.l"+{ return NETWORKLINE; }+	YY_BREAK+case 6:+YY_RULE_SETUP+#line 85 "../../src/foreign-pajek-lexer.l"+{ return VERTICESLINE; }+	YY_BREAK+case 7:+YY_RULE_SETUP+#line 86 "../../src/foreign-pajek-lexer.l"+{ return ARCSLINE; }+	YY_BREAK+case 8:+YY_RULE_SETUP+#line 87 "../../src/foreign-pajek-lexer.l"+{ return EDGESLINE; }+	YY_BREAK+case 9:+YY_RULE_SETUP+#line 88 "../../src/foreign-pajek-lexer.l"+{ return ARCSLISTLINE; }+	YY_BREAK+case 10:+YY_RULE_SETUP+#line 89 "../../src/foreign-pajek-lexer.l"+{ return EDGESLISTLINE; }+	YY_BREAK+case 11:+YY_RULE_SETUP+#line 90 "../../src/foreign-pajek-lexer.l"+{ return MATRIXLINE; }+	YY_BREAK+case 12:+/* rule 12 can match eol */+YY_RULE_SETUP+#line 91 "../../src/foreign-pajek-lexer.l"+{ yyextra->mode=0; return NEWLINE; }+	YY_BREAK+case 13:+/* rule 13 can match eol */+YY_RULE_SETUP+#line 92 "../../src/foreign-pajek-lexer.l"+{ return QSTR; }+	YY_BREAK+case 14:+/* rule 14 can match eol */+YY_RULE_SETUP+#line 93 "../../src/foreign-pajek-lexer.l"+{ return PSTR; }+	YY_BREAK+case 15:+YY_RULE_SETUP+#line 94 "../../src/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 97 "../../src/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 98 "../../src/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 99 "../../src/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 100 "../../src/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 101 "../../src/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 102 "../../src/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 103 "../../src/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 104 "../../src/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 105 "../../src/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 106 "../../src/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 108 "../../src/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 109 "../../src/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 110 "../../src/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 111 "../../src/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 112 "../../src/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 113 "../../src/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 114 "../../src/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 115 "../../src/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 116 "../../src/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 117 "../../src/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 118 "../../src/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 119 "../../src/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 120 "../../src/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 121 "../../src/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 123 "../../src/foreign-pajek-lexer.l"+{ if (yyextra->mode==1) { return VP_LPHI; } else+                             if (yyextra->mode==2) { return EP_LPHI; } else { return ALNUM; } }+	YY_BREAK+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 125 "../../src/foreign-pajek-lexer.l"+{ if (yyextra->mode==1) { return VP_LC; } else+                             if (yyextra->mode==2) { return EP_LC; } else { return ALNUM; } }+	YY_BREAK+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 127 "../../src/foreign-pajek-lexer.l"+{ if (yyextra->mode==1) { return VP_LR; } else+                             if (yyextra->mode==2) { return EP_LR; } else { return ALNUM; } }+	YY_BREAK+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 129 "../../src/foreign-pajek-lexer.l"+{ if (yyextra->mode==1) { return VP_LA; } else+                             if (yyextra->mode==2) { return EP_LA; } else { return ALNUM; } }+	YY_BREAK+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 131 "../../src/foreign-pajek-lexer.l"+{ if (yyextra->mode==1) { return VP_SIZE; } else +                             if (yyextra->mode==2) { return EP_SIZE; } else { return ALNUM; } }+	YY_BREAK+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 133 "../../src/foreign-pajek-lexer.l"+{ if (yyextra->mode==1) { return VP_FOS; } else +                             if (yyextra->mode==2) { return EP_FOS; } else { return ALNUM; } }+	YY_BREAK+case 46:+YY_RULE_SETUP+#line 136 "../../src/foreign-pajek-lexer.l"+{ return ALNUM; }+	YY_BREAK+case YY_STATE_EOF(INITIAL):+#line 138 "../../src/foreign-pajek-lexer.l"+{ if (yyextra->eof) {+                       yyterminate();+                    } else {+                       yyextra->eof=1;+                       return NEWLINE; +                    }+                  }+	YY_BREAK+case 47:+YY_RULE_SETUP+#line 146 "../../src/foreign-pajek-lexer.l"+{ return ERROR; }+	YY_BREAK+case 48:+YY_RULE_SETUP+#line 148 "../../src/foreign-pajek-lexer.l"+YY_FATAL_ERROR( "flex scanner jammed" );+	YY_BREAK+#line 1330 "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 "../../src/foreign-pajek-lexer.l"+++
+ igraph/src/foreign-pajek-parser.c view
@@ -0,0 +1,2815 @@+/* 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,+     ERROR = 270,+     VP_X_FACT = 271,+     VP_Y_FACT = 272,+     VP_IC = 273,+     VP_BC = 274,+     VP_LC = 275,+     VP_LR = 276,+     VP_LPHI = 277,+     VP_BW = 278,+     VP_FOS = 279,+     VP_PHI = 280,+     VP_R = 281,+     VP_Q = 282,+     VP_LA = 283,+     VP_FONT = 284,+     VP_URL = 285,+     VP_SIZE = 286,+     EP_C = 287,+     EP_S = 288,+     EP_A = 289,+     EP_W = 290,+     EP_H1 = 291,+     EP_H2 = 292,+     EP_A1 = 293,+     EP_A2 = 294,+     EP_K1 = 295,+     EP_K2 = 296,+     EP_AP = 297,+     EP_P = 298,+     EP_L = 299,+     EP_LP = 300,+     EP_LR = 301,+     EP_LPHI = 302,+     EP_LC = 303,+     EP_LA = 304,+     EP_SIZE = 305,+     EP_FOS = 306+   };+#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 ERROR 270+#define VP_X_FACT 271+#define VP_Y_FACT 272+#define VP_IC 273+#define VP_BC 274+#define VP_LC 275+#define VP_LR 276+#define VP_LPHI 277+#define VP_BW 278+#define VP_FOS 279+#define VP_PHI 280+#define VP_R 281+#define VP_Q 282+#define VP_LA 283+#define VP_FONT 284+#define VP_URL 285+#define VP_SIZE 286+#define EP_C 287+#define EP_S 288+#define EP_A 289+#define EP_W 290+#define EP_H1 291+#define EP_H2 292+#define EP_A1 293+#define EP_A2 294+#define EP_K1 295+#define EP_K2 296+#define EP_AP 297+#define EP_P 298+#define EP_L 299+#define EP_LP 300+#define EP_LR 301+#define EP_LPHI 302+#define EP_LC 303+#define EP_LA 304+#define EP_SIZE 305+#define EP_FOS 306+++++/* Copy the first part of user declarations.  */+#line 23 "../../src/foreign-pajek-parser.y"+++/* +   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@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 <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, +			 const 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 118 "../../src/foreign-pajek-parser.y"+{+  long int intnum;+  double   realnum;  +  struct {+    char *str;+    int len;+  } string;  +}+/* Line 193 of yacc.c.  */+#line 301 "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 326 "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  52+/* 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   306++#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,    51+};++#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[] =+{+      53,     0,    -1,    54,    55,    73,    -1,    -1,     8,   116,+       3,    -1,    56,     3,    57,    -1,     9,   114,    -1,     9,+     114,   114,    -1,    -1,    57,    58,    -1,     3,    -1,    60,+       3,    -1,    -1,    60,    59,    61,    62,    63,    64,     3,+      -1,   114,    -1,   117,    -1,    -1,   115,   115,    -1,   115,+     115,   115,    -1,    -1,   117,    -1,    -1,    64,    65,    -1,+      66,    -1,    16,   115,    -1,    17,   115,    -1,    18,   115,+     115,   115,    -1,    19,   115,   115,   115,    -1,    20,   115,+     115,   115,    -1,    21,   115,    -1,    22,   115,    -1,    23,+     115,    -1,    24,   115,    -1,    25,   115,    -1,    26,   115,+      -1,    27,   115,    -1,    28,   115,    -1,    31,   115,    -1,+      -1,    29,    67,    72,    -1,    -1,    30,    68,    72,    -1,+      -1,    18,    69,    72,    -1,    -1,    19,    70,    72,    -1,+      -1,    20,    71,    72,    -1,   117,    -1,    -1,    73,    74,+      -1,    73,    80,    -1,    73,    96,    -1,    73,   102,    -1,+      73,   108,    -1,    10,     3,    75,    -1,    10,   115,     3,+      75,    -1,    -1,    75,    76,    -1,     3,    -1,    -1,    78,+      79,    77,    86,    87,     3,    -1,   114,    -1,   114,    -1,+      11,     3,    81,    -1,    11,   115,     3,    81,    -1,    -1,+      81,    82,    -1,     3,    -1,    -1,    84,    85,    83,    86,+      87,     3,    -1,   114,    -1,   114,    -1,    -1,   115,    -1,+      -1,    87,    88,    -1,    89,    -1,    32,   115,   115,   115,+      -1,    33,   115,    -1,    35,   115,    -1,    36,   115,    -1,+      37,   115,    -1,    38,   115,    -1,    39,   115,    -1,    40,+     115,    -1,    41,   115,    -1,    42,   115,    -1,    45,   115,+      -1,    46,   115,    -1,    47,   115,    -1,    49,   115,    -1,+      50,   115,    -1,    51,   115,    -1,    -1,    34,    90,    95,+      -1,    -1,    43,    91,    95,    -1,    -1,    44,    92,    95,+      -1,    -1,    48,    93,    95,    -1,    -1,    32,    94,    95,+      -1,   117,    -1,    12,     3,    97,    -1,    -1,    97,    98,+      -1,     3,    -1,   100,    99,     3,    -1,    -1,    99,   101,+      -1,   114,    -1,   114,    -1,    13,     3,   103,    -1,    -1,+     103,   104,    -1,     3,    -1,   106,   105,     3,    -1,    -1,+     105,   107,    -1,   114,    -1,   114,    -1,   109,     3,   110,+      -1,    14,    -1,    -1,   110,   111,    -1,   112,     3,    -1,+      -1,   113,   112,    -1,   115,    -1,     4,    -1,     4,    -1,+      -1,   116,   117,    -1,     5,    -1,     4,    -1,     6,    -1+};++/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */+static const yytype_uint16 yyrline[] =+{+       0,   192,   192,   196,   196,   198,   200,   204,   210,   210,+     212,   213,   214,   214,   217,   219,   224,   225,   229,   235,+     235,   239,   239,   242,   243,   246,   249,   254,   259,   264,+     267,   270,   273,   276,   279,   282,   285,   288,   293,   293,+     297,   297,   301,   301,   305,   305,   310,   310,   317,   319,+     319,   319,   319,   319,   319,   321,   322,   324,   324,   326,+     327,   327,   333,   335,   337,   338,   340,   340,   342,   343,+     343,   349,   351,   353,   353,   357,   357,   360,   361,   366,+     369,   372,   375,   378,   381,   384,   387,   390,   393,   396,+     399,   402,   405,   408,   413,   413,   417,   417,   421,   421,+     425,   425,   429,   429,   435,   437,   439,   439,   441,   441,+     443,   443,   445,   447,   452,   454,   454,   456,   456,   458,+     458,   460,   462,   469,   471,   476,   476,   478,   480,   480,+     482,   502,   505,   508,   508,   510,   512,   514+};+#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", "ERROR", "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,   306+};+# endif++/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */+static const yytype_uint8 yyr1[] =+{+       0,    52,    53,    54,    54,    55,    56,    56,    57,    57,+      58,    58,    59,    58,    60,    61,    62,    62,    62,    63,+      63,    64,    64,    65,    65,    65,    65,    65,    65,    65,+      65,    65,    65,    65,    65,    65,    65,    65,    67,    66,+      68,    66,    69,    66,    70,    66,    71,    66,    72,    73,+      73,    73,    73,    73,    73,    74,    74,    75,    75,    76,+      77,    76,    78,    79,    80,    80,    81,    81,    82,    83,+      82,    84,    85,    86,    86,    87,    87,    88,    88,    88,+      88,    88,    88,    88,    88,    88,    88,    88,    88,    88,+      88,    88,    88,    88,    90,    89,    91,    89,    92,    89,+      93,    89,    94,    89,    95,    96,    97,    97,    98,    98,+      99,    99,   100,   101,   102,   103,   103,   104,   104,   105,+     105,   106,   107,   108,   109,   110,   110,   111,   112,   112,+     113,   114,   115,   116,   116,   117,   117,   117+};++/* 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,+     219,  -167,   150,   170,  -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,   123,     0,     0,     0,     0,     0,     0,+       0,     0,     0,     0,   197,     0,     0,   197,     0,     0,+     203,     0,   204,   146,   205,     0,   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,   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,     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,     3,    -1,    -1,    -1,    -1,    -1,    -1,+      -1,    -1,    -1,    -1,   166,    -1,    -1,   169,    -1,    -1,+     189,    -1,   191,     3,   193,    -1,   178,   179,    -1,   198,+      -1,   183,    32,    33,    34,    35,    36,    37,    38,    39,+      40,    41,    42,    43,    44,    45,    46,    47,    48,    49,+      50,    51,    32,    33,    34,    35,    36,    37,    38,    39,+      40,    41,    42,    43,    44,    45,    46,    47,    48,    49,+      50,    51,     3,    -1,    -1,    -1,    -1,    -1,    -1,    -1,+      -1,    -1,    -1,    -1,    -1,    16,    17,    18,    19,    20,+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,+      31+};++/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing+   symbol of state STATE-NUM.  */+static const yytype_uint8 yystos[] =+{+       0,     8,    53,    54,   116,     0,     9,    55,    56,     3,+       4,     5,     6,   117,     4,   114,    73,     3,   114,    10,+      11,    12,    13,    14,    74,    80,    96,   102,   108,   109,+      57,     3,     4,   115,     3,   115,     3,     3,     3,     3,+      58,    60,   114,    75,     3,    81,     3,    97,   103,   110,+       3,    59,     3,    76,    78,   114,    75,     3,    82,    84,+     114,    81,     3,    98,   100,   114,     3,   104,   106,   114,+     111,   112,   113,   115,    61,   117,    79,   114,    85,   114,+      99,   105,     3,   112,    62,   115,    77,    83,     3,   101,+     114,     3,   107,   114,    63,   117,   115,    86,   115,    86,+      64,   115,    87,    87,     3,    16,    17,    18,    19,    20,+      21,    22,    23,    24,    25,    26,    27,    28,    29,    30,+      31,    65,    66,     3,    32,    33,    34,    35,    36,    37,+      38,    39,    40,    41,    42,    43,    44,    45,    46,    47,+      48,    49,    50,    51,    88,    89,     3,   115,   115,    69,+     115,    70,   115,    71,   115,   115,   115,   115,   115,   115,+     115,   115,   115,    67,    68,   115,    94,   115,   115,    90,+     115,   115,   115,   115,   115,   115,   115,   115,    91,    92,+     115,   115,   115,    93,   115,   115,   115,    72,   117,   115,+      72,   115,    72,   115,    72,    72,    95,   117,   115,    95,+      95,    95,    95,   115,   115,   115,   115+};++#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 192 "../../src/foreign-pajek-parser.y"+    {+  if (context->vcount2 > 0) { igraph_i_pajek_check_bipartite(context); }+ }+    break;++  case 6:+#line 200 "../../src/foreign-pajek-parser.y"+    { +  context->vcount=(yyvsp[(2) - (2)].intnum); +  context->vcount2=0;+            }+    break;++  case 7:+#line 204 "../../src/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 214 "../../src/foreign-pajek-parser.y"+    { context->actvertex=(yyvsp[(1) - (1)].intnum); }+    break;++  case 13:+#line 214 "../../src/foreign-pajek-parser.y"+    { }+    break;++  case 14:+#line 217 "../../src/foreign-pajek-parser.y"+    { (yyval.intnum)=(yyvsp[(1) - (1)].intnum); context->mode=1; }+    break;++  case 15:+#line 219 "../../src/foreign-pajek-parser.y"+    {+  igraph_i_pajek_add_string_vertex_attribute("id", (yyvsp[(1) - (1)].string).str, (yyvsp[(1) - (1)].string).len, context);+  igraph_i_pajek_add_string_vertex_attribute("name", (yyvsp[(1) - (1)].string).str, (yyvsp[(1) - (1)].string).len, context);+}+    break;++  case 17:+#line 225 "../../src/foreign-pajek-parser.y"+    { +  igraph_i_pajek_add_numeric_vertex_attribute("x", (yyvsp[(1) - (2)].realnum), context);+  igraph_i_pajek_add_numeric_vertex_attribute("y", (yyvsp[(2) - (2)].realnum), context);+	    }+    break;++  case 18:+#line 229 "../../src/foreign-pajek-parser.y"+    { +  igraph_i_pajek_add_numeric_vertex_attribute("x", (yyvsp[(1) - (3)].realnum), context);+  igraph_i_pajek_add_numeric_vertex_attribute("y", (yyvsp[(2) - (3)].realnum), context);+  igraph_i_pajek_add_numeric_vertex_attribute("z", (yyvsp[(3) - (3)].realnum), context);+	    }+    break;++  case 20:+#line 235 "../../src/foreign-pajek-parser.y"+    { +  igraph_i_pajek_add_string_vertex_attribute("shape", (yyvsp[(1) - (1)].string).str, (yyvsp[(1) - (1)].string).len, context);+}+    break;++  case 24:+#line 243 "../../src/foreign-pajek-parser.y"+    {+	 igraph_i_pajek_add_numeric_vertex_attribute("xfact", (yyvsp[(2) - (2)].realnum), context);+       }+    break;++  case 25:+#line 246 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("yfact", (yyvsp[(2) - (2)].realnum), context);+       }+    break;++  case 26:+#line 249 "../../src/foreign-pajek-parser.y"+    { /* RGB color */+         igraph_i_pajek_add_numeric_vertex_attribute("color-red", (yyvsp[(2) - (4)].realnum), context);+	 igraph_i_pajek_add_numeric_vertex_attribute("color-green", (yyvsp[(3) - (4)].realnum), context);+	 igraph_i_pajek_add_numeric_vertex_attribute("color-blue", (yyvsp[(4) - (4)].realnum), context);+       }+    break;++  case 27:+#line 254 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("framecolor-red", (yyvsp[(2) - (4)].realnum), context);+	 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-green", (yyvsp[(3) - (4)].realnum), context);+	 igraph_i_pajek_add_numeric_vertex_attribute("framecolor-blue", (yyvsp[(4) - (4)].realnum), context);+       }+    break;++  case 28:+#line 259 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-red", (yyvsp[(2) - (4)].realnum), context);+	 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-green", (yyvsp[(3) - (4)].realnum), context);+	 igraph_i_pajek_add_numeric_vertex_attribute("labelcolor-blue", (yyvsp[(4) - (4)].realnum), context);+       }+    break;++  case 29:+#line 264 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("labeldist", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 30:+#line 267 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("labeldegree2", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 31:+#line 270 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("framewidth", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 32:+#line 273 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("fontsize", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 33:+#line 276 "../../src/foreign-pajek-parser.y"+    {       +         igraph_i_pajek_add_numeric_vertex_attribute("rotation", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 34:+#line 279 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("radius", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 35:+#line 282 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("diamondratio", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 36:+#line 285 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("labeldegree", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 37:+#line 288 "../../src/foreign-pajek-parser.y"+    {+         igraph_i_pajek_add_numeric_vertex_attribute("vertexsize", (yyvsp[(2) - (2)].realnum), context);+     }+    break;++  case 38:+#line 293 "../../src/foreign-pajek-parser.y"+    { context->mode=3; }+    break;++  case 39:+#line 293 "../../src/foreign-pajek-parser.y"+    { +         context->mode=1;+	 igraph_i_pajek_add_string_vertex_attribute("font", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+     }+    break;++  case 40:+#line 297 "../../src/foreign-pajek-parser.y"+    { context->mode=3; }+    break;++  case 41:+#line 297 "../../src/foreign-pajek-parser.y"+    {+         context->mode=1;+	 igraph_i_pajek_add_string_vertex_attribute("url", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+     }+    break;++  case 42:+#line 301 "../../src/foreign-pajek-parser.y"+    { context->mode=3; }+    break;++  case 43:+#line 301 "../../src/foreign-pajek-parser.y"+    {+         context->mode=1;+	 igraph_i_pajek_add_string_vertex_attribute("color", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+     }+    break;++  case 44:+#line 305 "../../src/foreign-pajek-parser.y"+    { context->mode=3; }+    break;++  case 45:+#line 305 "../../src/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 310 "../../src/foreign-pajek-parser.y"+    { context->mode=3; }+    break;++  case 47:+#line 310 "../../src/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 317 "../../src/foreign-pajek-parser.y"+    { (yyval.string)=(yyvsp[(1) - (1)].string); }+    break;++  case 55:+#line 321 "../../src/foreign-pajek-parser.y"+    { context->directed=1; }+    break;++  case 56:+#line 322 "../../src/foreign-pajek-parser.y"+    { context->directed=1; }+    break;++  case 60:+#line 327 "../../src/foreign-pajek-parser.y"+    { context->actedge++;+	                  context->mode=2; }+    break;++  case 61:+#line 328 "../../src/foreign-pajek-parser.y"+    { +  igraph_vector_push_back(context->vector, (yyvsp[(1) - (6)].intnum)-1);+  igraph_vector_push_back(context->vector, (yyvsp[(2) - (6)].intnum)-1); }+    break;++  case 64:+#line 337 "../../src/foreign-pajek-parser.y"+    { context->directed=0; }+    break;++  case 65:+#line 338 "../../src/foreign-pajek-parser.y"+    { context->directed=0; }+    break;++  case 69:+#line 343 "../../src/foreign-pajek-parser.y"+    { context->actedge++; +	                    context->mode=2; }+    break;++  case 70:+#line 344 "../../src/foreign-pajek-parser.y"+    { +  igraph_vector_push_back(context->vector, (yyvsp[(1) - (6)].intnum)-1);+  igraph_vector_push_back(context->vector, (yyvsp[(2) - (6)].intnum)-1); }+    break;++  case 74:+#line 353 "../../src/foreign-pajek-parser.y"+    {+  igraph_i_pajek_add_numeric_edge_attribute("weight", (yyvsp[(1) - (1)].realnum), context);+}+    break;++  case 78:+#line 361 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("color-red", (yyvsp[(2) - (4)].realnum), context);+       igraph_i_pajek_add_numeric_edge_attribute("color-green", (yyvsp[(3) - (4)].realnum), context);+       igraph_i_pajek_add_numeric_edge_attribute("color-blue", (yyvsp[(4) - (4)].realnum), context);+   }+    break;++  case 79:+#line 366 "../../src/foreign-pajek-parser.y"+    { +       igraph_i_pajek_add_numeric_edge_attribute("arrowsize", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 80:+#line 369 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("edgewidth", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 81:+#line 372 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("hook1", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 82:+#line 375 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("hook2", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 83:+#line 378 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("angle1", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 84:+#line 381 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("angle2", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 85:+#line 384 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("velocity1", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 86:+#line 387 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("velocity2", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 87:+#line 390 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("arrowpos", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 88:+#line 393 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("labelpos", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 89:+#line 396 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("labelangle", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 90:+#line 399 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("labelangle2", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 91:+#line 402 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("labeldegree", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 92:+#line 405 "../../src/foreign-pajek-parser.y"+    {		/* what is this??? */+       igraph_i_pajek_add_numeric_edge_attribute("arrowsize", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 93:+#line 408 "../../src/foreign-pajek-parser.y"+    {+       igraph_i_pajek_add_numeric_edge_attribute("fontsize", (yyvsp[(2) - (2)].realnum), context);+   }+    break;++  case 94:+#line 413 "../../src/foreign-pajek-parser.y"+    { context->mode=4; }+    break;++  case 95:+#line 413 "../../src/foreign-pajek-parser.y"+    {+      context->mode=2;+      igraph_i_pajek_add_string_edge_attribute("arrowtype", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+    }+    break;++  case 96:+#line 417 "../../src/foreign-pajek-parser.y"+    { context->mode=4; }+    break;++  case 97:+#line 417 "../../src/foreign-pajek-parser.y"+    {+      context->mode=2;+      igraph_i_pajek_add_string_edge_attribute("linepattern", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+    }+    break;++  case 98:+#line 421 "../../src/foreign-pajek-parser.y"+    { context->mode=4; }+    break;++  case 99:+#line 421 "../../src/foreign-pajek-parser.y"+    {+      context->mode=2;+      igraph_i_pajek_add_string_edge_attribute("label", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+    }+    break;++  case 100:+#line 425 "../../src/foreign-pajek-parser.y"+    { context->mode=4; }+    break;++  case 101:+#line 425 "../../src/foreign-pajek-parser.y"+    {+      context->mode=2;+      igraph_i_pajek_add_string_edge_attribute("labelcolor", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+    }+    break;++  case 102:+#line 429 "../../src/foreign-pajek-parser.y"+    { context->mode=4; }+    break;++  case 103:+#line 429 "../../src/foreign-pajek-parser.y"+    {+      context->mode=2;+      igraph_i_pajek_add_string_edge_attribute("color", (yyvsp[(3) - (3)].string).str, (yyvsp[(3) - (3)].string).len, context);+    }+    break;++  case 104:+#line 435 "../../src/foreign-pajek-parser.y"+    { context->mode=2; (yyval.string)=(yyvsp[(1) - (1)].string); }+    break;++  case 105:+#line 437 "../../src/foreign-pajek-parser.y"+    { context->directed=1; }+    break;++  case 112:+#line 445 "../../src/foreign-pajek-parser.y"+    { context->mode=0; context->actfrom=labs((yyvsp[(1) - (1)].intnum))-1; }+    break;++  case 113:+#line 447 "../../src/foreign-pajek-parser.y"+    { +  igraph_vector_push_back(context->vector, context->actfrom); +  igraph_vector_push_back(context->vector, labs((yyvsp[(1) - (1)].intnum))-1); +}+    break;++  case 114:+#line 452 "../../src/foreign-pajek-parser.y"+    { context->directed=0; }+    break;++  case 121:+#line 460 "../../src/foreign-pajek-parser.y"+    { context->mode=0; context->actfrom=labs((yyvsp[(1) - (1)].intnum))-1; }+    break;++  case 122:+#line 462 "../../src/foreign-pajek-parser.y"+    { +  igraph_vector_push_back(context->vector, context->actfrom); +  igraph_vector_push_back(context->vector, labs((yyvsp[(1) - (1)].intnum))-1); +}+    break;++  case 124:+#line 471 "../../src/foreign-pajek-parser.y"+    { context->actfrom=0; +                         context->actto=0; +                         context->directed=(context->vcount2==0);+                       }+    break;++  case 127:+#line 478 "../../src/foreign-pajek-parser.y"+    { context->actfrom++; context->actto=0; }+    break;++  case 130:+#line 482 "../../src/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 502 "../../src/foreign-pajek-parser.y"+    { (yyval.intnum)=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),+					  igraph_pajek_yyget_leng(scanner)); }+    break;++  case 132:+#line 505 "../../src/foreign-pajek-parser.y"+    { (yyval.realnum)=igraph_pajek_get_number(igraph_pajek_yyget_text(scanner),+					  igraph_pajek_yyget_leng(scanner)); }+    break;++  case 135:+#line 510 "../../src/foreign-pajek-parser.y"+    { (yyval.string).str=igraph_pajek_yyget_text(scanner); +              (yyval.string).len=igraph_pajek_yyget_leng(scanner); }+    break;++  case 136:+#line 512 "../../src/foreign-pajek-parser.y"+    { (yyval.string).str=igraph_pajek_yyget_text(scanner); +              (yyval.string).len=igraph_pajek_yyget_leng(scanner); }+    break;++  case 137:+#line 514 "../../src/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 2356 "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 517 "../../src/foreign-pajek-parser.y"+++int igraph_pajek_yyerror(YYLTYPE* locp, +			 igraph_i_pajek_parsedata_t *context, +			 const 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;+}+
+ igraph/src/foreign.c view
@@ -0,0 +1,3390 @@+/* -*- mode: C -*-  */+/*+   IGraph R package.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+    igraph_integer_t no_of_nodes;+    long int no_predefined = 0;+    igraph_vector_ptr_t name, weight;+    igraph_vector_ptr_t *pname = 0, *pweight = 0;+    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 = &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[0] != 0) {+            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;+    }++    if (igraph_vector_empty(&edges)) {+        no_of_nodes = 0;+    } else {+        no_of_nodes = igraph_vector_max(&edges) + 1;+    }++    IGRAPH_CHECK(igraph_add_vertices(graph, no_of_nodes, pname));+    IGRAPH_CHECK(igraph_add_edges(graph, &edges, pweight));++    if (pname) {+        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 = &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[0] != 0) {+            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[0] != 0) {+            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[0] != 0) {+            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 or 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;++    /* first, check whether the string is equal to some reserved word */+    if (!strcasecmp(orig, "graph") || !strcasecmp(orig, "digraph") ||+        !strcasecmp(orig, "node") || !strcasecmp(orig, "edge") ||+        !strcasecmp(orig, "strict") || !strcasecmp(orig, "subgraph")) {+        need_quote = 1;+        is_number = 0;+    }++    /* next, check whether we need to escape the string for any other reason.+     * Also update is_number and newlen */+    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[0] != 0) {+            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 */+    if (n2 > 0) {+        n = (long int) igraph_vector_max(&context.edges);+    } else {+        n = 0;+    }+    if (n >= context.n) {+        IGRAPH_WARNING("More vertices than specified in `DL' file");+        context.n = n;+    }++    /* 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++
+ igraph/src/forestfire.c view
@@ -0,0 +1,264 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/fortran_intrinsics.c view
@@ -0,0 +1,53 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-12  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge MA, 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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;+}+
+ igraph/src/ftell_.c view
@@ -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
+ igraph/src/games.c view
@@ -0,0 +1,4784 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;++    if (!directed) {+        outpref = 1;+    }++    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;++    if (!directed) {+        outpref = 1;+    }++    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;++    if (!directed) {+        outpref = 1;+    }++    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&aacute;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. Ignored and assumed to be true if the graph+ *        being generated is undirected.+ * \param A The probability that a vertex is cited is proportional to+ *        d^power+A, where d is its degree (see also the \p outpref+ *        argument), power and A are given by arguments. In the+ *        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 former+ *        case, the starting configuration is a clique of size \p m.+ *        In the latter case, the graph is 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 obscure parameterizations */+    if (outseq && igraph_vector_size(outseq) == 0) {+        outseq = 0;+    }+    if (!directed) {+        outpref = 1;+    }++    /* 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 (!outpref && A <= 0) {+        IGRAPH_ERROR("Constant attractiveness (A) must be positive",+                     IGRAPH_EINVAL);+    }+    if (outpref && A < 0) {+        IGRAPH_ERROR("Constant attractiveness (A) must be non-negative",+                     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 (n == 0) {+        return igraph_empty(graph, 0, directed);+    }++    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;+}++int igraph_degree_sequence_game_no_multiple_undirected_uniform(igraph_t *graph, const igraph_vector_t *degseq) {+    igraph_vector_int_t stubs;+    igraph_vector_t edges;+    igraph_bool_t degseq_ok;+    igraph_vector_ptr_t adjlist;+    long i, j, k;+    long vcount, ecount, stub_count;++    IGRAPH_CHECK(igraph_is_graphical_degree_sequence(degseq, 0, &degseq_ok));+    if (!degseq_ok) {+        IGRAPH_ERROR("No simple undirected graph can realize the given degree sequence", IGRAPH_EINVAL);+    }++    stub_count = (long) igraph_vector_sum(degseq);+    ecount = stub_count / 2;+    vcount = igraph_vector_size(degseq);++    IGRAPH_VECTOR_INT_INIT_FINALLY(&stubs, stub_count);+    IGRAPH_VECTOR_INIT_FINALLY(&edges, stub_count);++    k = 0;+    for (i = 0; i < vcount; ++i) {+        long deg = (long) VECTOR(*degseq)[i];+        for (j = 0; j < deg; ++j) {+            VECTOR(stubs)[k++] = i;+        }+    }++    IGRAPH_CHECK(igraph_vector_ptr_init(&adjlist, vcount));+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&adjlist, igraph_set_destroy);+    for (i = 0; i < vcount; ++i) {+        igraph_set_t *set = igraph_malloc(sizeof(igraph_set_t));+        if (! set) {+            IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM);+        }+        IGRAPH_CHECK(igraph_set_init(set, 0));+        VECTOR(adjlist)[i] = set;+        IGRAPH_CHECK(igraph_set_reserve(set, (long) VECTOR(*degseq)[i]));+    }+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);++    RNG_BEGIN();++    for (;;) {+        igraph_bool_t success = 1;+        IGRAPH_CHECK(igraph_vector_int_shuffle(&stubs));++        for (i = 0; i < ecount; ++i) {+            igraph_integer_t from = VECTOR(stubs)[2 * i];+            igraph_integer_t to = VECTOR(stubs)[2 * i + 1];++            /* loop edge, fail */+            if (to == from) {+                success = 0;+                break;+            }++            /* multi-edge, fail */+            if (igraph_set_contains((igraph_set_t *) VECTOR(adjlist)[to], from)) {+                success = 0;+                break;+            }++            /* sets are already reserved */+            igraph_set_add((igraph_set_t *) VECTOR(adjlist)[to], from);+            igraph_set_add((igraph_set_t *) VECTOR(adjlist)[from], to);++            /* register edge */+            VECTOR(edges)[2 * i]   = from;+            VECTOR(edges)[2 * i + 1] = to;+        }++        if (success) {+            break;+        }++        IGRAPH_ALLOW_INTERRUPTION();++        for (j = 0; j < vcount; ++j) {+            igraph_set_clear((igraph_set_t *) VECTOR(adjlist)[j]);+        }+    }++    RNG_END();++    igraph_vector_ptr_destroy_all(&adjlist);+    igraph_vector_int_destroy(&stubs);+    IGRAPH_FINALLY_CLEAN(2);++    IGRAPH_CHECK(igraph_create(graph, &edges, vcount, /* directed = */ 0));++    igraph_vector_destroy(&edges);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}++int igraph_degree_sequence_game_no_multiple_directed_uniform(+    igraph_t *graph, const igraph_vector_t *out_deg, const igraph_vector_t *in_deg) {+    igraph_vector_int_t out_stubs, in_stubs;+    igraph_vector_t edges;+    igraph_bool_t degseq_ok;+    igraph_vector_ptr_t adjlist;+    long i, j, k, l;+    long vcount, ecount;++    IGRAPH_CHECK(igraph_is_graphical_degree_sequence(out_deg, in_deg, &degseq_ok));+    if (!degseq_ok) {+        IGRAPH_ERROR("No simple directed graph can realize the given degree sequence", IGRAPH_EINVAL);+    }++    ecount = (long) igraph_vector_sum(out_deg);+    vcount = igraph_vector_size(out_deg);++    IGRAPH_VECTOR_INT_INIT_FINALLY(&out_stubs, ecount);+    IGRAPH_VECTOR_INT_INIT_FINALLY(&in_stubs, ecount);+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * ecount);++    k = 0; l = 0;+    for (i = 0; i < vcount; ++i) {+        long dout, din;++        dout = (long) VECTOR(*out_deg)[i];+        for (j = 0; j < dout; ++j) {+            VECTOR(out_stubs)[k++] = i;+        }++        din  = (long) VECTOR(*in_deg)[i];+        for (j = 0; j < din; ++j) {+            VECTOR(in_stubs)[l++] = i;+        }+    }++    IGRAPH_CHECK(igraph_vector_ptr_init(&adjlist, vcount));+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&adjlist, igraph_set_destroy);+    for (i = 0; i < vcount; ++i) {+        igraph_set_t *set = igraph_malloc(sizeof(igraph_set_t));+        if (! set) {+            IGRAPH_ERROR("Out of memory", IGRAPH_ENOMEM);+        }+        IGRAPH_CHECK(igraph_set_init(set, 0));+        VECTOR(adjlist)[i] = set;+        IGRAPH_CHECK(igraph_set_reserve(set, (long) VECTOR(*out_deg)[i]));+    }+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &adjlist);++    RNG_BEGIN();++    for (;;) {+        igraph_bool_t success = 1;+        IGRAPH_CHECK(igraph_vector_int_shuffle(&out_stubs));++        for (i = 0; i < ecount; ++i) {+            igraph_integer_t from = VECTOR(out_stubs)[i];+            igraph_integer_t to = VECTOR(in_stubs)[i];+            igraph_set_t *set;++            /* loop edge, fail */+            if (to == from) {+                success = 0;+                break;+            }++            /* multi-edge, fail */+            set = (igraph_set_t *) VECTOR(adjlist)[from];+            if (igraph_set_contains(set, to)) {+                success = 0;+                break;+            }++            /* sets are already reserved */+            igraph_set_add(set, to);++            /* register edge */+            VECTOR(edges)[2 * i]   = from;+            VECTOR(edges)[2 * i + 1] = to;+        }++        if (success) {+            break;+        }++        IGRAPH_ALLOW_INTERRUPTION();++        for (j = 0; j < vcount; ++j) {+            igraph_set_clear((igraph_set_t *) VECTOR(adjlist)[j]);+        }+    }++    RNG_END();++    igraph_vector_ptr_destroy_all(&adjlist);+    igraph_vector_int_destroy(&out_stubs);+    igraph_vector_int_destroy(&in_stubs);+    IGRAPH_FINALLY_CLEAN(3);++    IGRAPH_CHECK(igraph_create(graph, &edges, vcount, /* directed = */ 1));++    igraph_vector_destroy(&edges);+    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+ *          This method implements the configuration model.+ *          For undirected graphs, it puts all vertex IDs in a bag+ *          such that the multiplicity of a vertex in the bag is the same as+ *          its degree. Then it draws pairs from the bag until the bag becomes+ *          empty. This method can generate both loop (self) edges and multiple+ *          edges. For directed graphs, the algorithm is basically the same,+ *          but two separate bags are used for the in- and out-degrees.+ *          Undirected graphs are generated with probability proportional to+ *          <code>(\prod_{i&lt;j} A_{ij} ! \prod_i A_{ii} !!)^{-1}</code>,+ *          where \c A denotes the adjacency matrix and <code>!!</code> denotes+ *          the double factorial.+ *          The corresponding  expression for directed ones is+ *          <code>(\prod_{i,j} A_{ij}!)^{-1}</code>.+ *          Thus the probability of all simple graphs (which only have 0s and 1s+ *          in the adjacency matrix) is the same, while that of+ *          non-simple ones depends on their structure.+ *          \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_SIMPLE_NO_MULTIPLE_UNIFORM+ *          This method is identical to \c IGRAPH_DEGSEQ_SIMPLE, but if the+ *          generated graph is not simple, it rejects it and re-starts the+ *          generation. It samples all simple graphs with the same probability.+ *          \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; for the algorithm,+ *          see https://www-complexnetworks.lip6.fr/~latapy/FV/generation.html+ *          and the paper https://arxiv.org/abs/cs/0502085+ *        \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) {+    if (in_deg && igraph_vector_empty(in_deg) && !igraph_vector_empty(out_deg)) {+        in_deg = 0;+    }++    switch (method) {+    case IGRAPH_DEGSEQ_SIMPLE:+        return igraph_degree_sequence_game_simple(graph, out_deg, in_deg);++    case IGRAPH_DEGSEQ_VL:+        return igraph_degree_sequence_game_vl(graph, out_deg, in_deg);++    case IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE:+        if (in_deg == 0) {+            return igraph_degree_sequence_game_no_multiple_undirected(graph, out_deg);+        } else {+            return igraph_degree_sequence_game_no_multiple_directed(graph, out_deg, in_deg);+        }++    case IGRAPH_DEGSEQ_SIMPLE_NO_MULTIPLE_UNIFORM:+        if (in_deg == 0) {+            return igraph_degree_sequence_game_no_multiple_undirected_uniform(graph, out_deg);+        } else {+            return igraph_degree_sequence_game_no_multiple_directed_uniform(graph, out_deg, in_deg);+        }++    default:+        IGRAPH_ERROR("Invalid degree sequence game method", IGRAPH_EINVAL);+    }+}++/**+ * \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_rewire_directed_edges+ * \brief Rewire the chosen endpoint of directed edges+ *+ * This function rewires either the start or end of directed edges in a graph+ * with a constant probability. Correspondingly, either the in-degree sequence+ * or the out-degree sequence of the graph will be preserved.+ *+ * </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. If it is directed, \ref igraph_rewire_edges()+ *    will be called.+ * \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 mode The endpoints of directed edges to rewire. It is ignored for+ *    undirected graphs. Possible values:+ *        \clist+ *        \cli IGRAPH_OUT+ *          rewire the end of each directed edge+ *        \cli IGRAPH_IN+ *          rewire the start of each directed edge+ *        \cli IGRAPH_ALL+ *          rewire both endpoints of each edge+ *        \endclist+ * \return Error code.+ *+ * \sa \ref igraph_rewire_edges(), \ref igraph_rewire()+ *+ * Time complexity: O(|E|).+ */++int igraph_rewire_directed_edges(igraph_t *graph, igraph_real_t prob,+                                 igraph_bool_t loops, igraph_neimode_t mode) {++    if (prob < 0 || prob > 1) {+        IGRAPH_ERROR("Rewiring probability should be between zero and one",+                     IGRAPH_EINVAL);+    }++    if (mode != IGRAPH_OUT && mode != IGRAPH_IN &&+        mode != IGRAPH_ALL) {+        IGRAPH_ERROR("Invalid mode argument", IGRAPH_EINVMODE);+    }++    if (prob == 0) {+        return IGRAPH_SUCCESS;+    }++    if (igraph_is_directed(graph) && mode != IGRAPH_ALL) {+        igraph_t newgraph;+        long int no_of_edges = igraph_ecount(graph);+        long int no_of_nodes = igraph_vcount(graph);+        long int to_rewire;+        long int offset;+        igraph_vector_t edges;++        IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * no_of_edges);++        switch (mode) {+        case IGRAPH_IN:+            offset = 0;+            break;+        case IGRAPH_OUT:+            offset = 1;+            break;+        case IGRAPH_ALL:+            break; /* suppress compiler warning */+        }++        IGRAPH_CHECK(igraph_get_edgelist(graph, &edges, 0));++        RNG_BEGIN();++        to_rewire = RNG_GEOM(prob);+        while (to_rewire < no_of_edges) {+            if (loops) {+                VECTOR(edges)[2 * to_rewire + offset] = RNG_INTEGER(0, no_of_nodes - 1);+            } else {+                long int nei = (long int) VECTOR(edges)[2 * to_rewire + (1 - offset)];+                long int r = RNG_INTEGER(0, no_of_nodes - 2);+                VECTOR(edges)[2 * to_rewire + offset] = (r != nei ? r : no_of_nodes - 1);+            }+            to_rewire += RNG_GEOM(prob) + 1;+        }++        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;++    } else {+        IGRAPH_CHECK(igraph_rewire_edges(graph, prob, loops, /* multiple = */ 0));+    }++    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, nnval, type;++    if (igraph_vector_size(types) != nodes) {+        IGRAPH_ERROR("Invalid size of types", IGRAPH_EINVAL);+    }++    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);++    /* return an empty graph is nodes is zero */+    if (nodes == 0) {+        igraph_create(graph, &edges, nodes, directed);+        igraph_vector_destroy(&edges);+        IGRAPH_FINALLY_CLEAN(1);+        return 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;+    type = (long int) VECTOR(*types)[0];+    if (type >= igraph_vector_size(pref)) {+        IGRAPH_ERROR("pref is too short for the given types", IGRAPH_EINVAL);+    }+    nnval = VECTOR(*pref)[type];+    if (nnval < 0) {+        IGRAPH_ERROR("pref contains negative entries", IGRAPH_EINVAL);+    }+    sum = VECTOR(cumsum)[1] = nnval;++    RNG_BEGIN();++    for (i = 1; i < nodes; i++) {+        for (j = 0; j < edges_per_step; j++) {+            long int to;+            if (sum > 0) {+                igraph_vector_binsearch(&cumsum, RNG_UNIF(0, sum), &to);+            } else {+                to = i + 1;+            }+            igraph_vector_push_back(&edges, i);+            igraph_vector_push_back(&edges, to - 1);+        }+        type = (long int) VECTOR(*types)[i];+        if (type >= igraph_vector_size(pref)) {+            IGRAPH_ERROR("pref is too short for the given types", IGRAPH_EINVAL);+        }+        nnval = VECTOR(*pref)[type];+        if (nnval < 0) {+            IGRAPH_ERROR("pref contains negative entries", IGRAPH_EINVAL);+        }+        sum += nnval;+        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;+    long int i, j;++    if (igraph_vector_size(types) != nodes) {+        IGRAPH_ERROR("Invalid size of types", IGRAPH_EINVAL);+    }++    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);++    /* return an empty graph is nodes is zero */+    if (nodes == 0) {+        igraph_create(graph, &edges, nodes, directed);+        igraph_vector_destroy(&edges);+        IGRAPH_FINALLY_CLEAN(2); /* str and edges */+        return 0;+    }++    nocats = igraph_matrix_ncol(pref);+    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];+        if ( MATRIX(*pref, i, type) < 0) {+            IGRAPH_ERROR("pref contains negative entries", IGRAPH_EINVAL);+        }+        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++) {+            if ( MATRIX(*pref, j, type) < 0) {+                IGRAPH_ERROR("pref contains negative entries", IGRAPH_EINVAL);+            }+            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_integer_t outnodes, innodes, 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_real_t max_no_of_edges;+    igraph_bool_t is_directed = (fitness_in != 0);+    float num_steps;+    igraph_integer_t step_counter = 0;+    long int i, 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;+    }++    if (is_directed && igraph_vector_size(fitness_in) != no_of_nodes) {+        IGRAPH_ERROR("fitness_in must have the same size as fitness_out", IGRAPH_EINVAL);+    }++    /* 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);+    }++    /* Avoid getting into an infinite loop when too many edges are requested */+    if (!multiple) {+        if (is_directed) {+            outnodes = innodes = nodes = 0;+            for (i = 0; i < no_of_nodes; i++) {+                if (VECTOR(*fitness_out)[i] != 0) {+                    outnodes++;+                }+                if (VECTOR(*fitness_in)[i] != 0) {+                    innodes++;+                }+                if (VECTOR(*fitness_out)[i] != 0 && VECTOR(*fitness_in)[i] != 0) {+                    nodes++;+                }+            }+            max_no_of_edges = ((igraph_real_t) outnodes) * innodes - (loops ? 0 : nodes);+        } else {+            nodes = 0;+            for (i = 0; i < no_of_nodes; i++) {+                if (VECTOR(*fitness_out)[i] != 0) {+                    nodes++;+                }+            }+            max_no_of_edges = loops+                              ? nodes * ((igraph_real_t)nodes + 1) / 2+                              : nodes * ((igraph_real_t)nodes - 1) / 2;+        }+        if (no_of_edges > max_no_of_edges) {+            IGRAPH_ERROR("Too many edges requested", 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 ((step_counter++) % 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 ((step_counter++) % 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;+}++/**+ * \function igraph_correlated_game+ * Generate pairs of correlated random graphs+ *+ * Sample a new graph by perturbing the adjacency matrix of a+ * given graph and shuffling its vertices.+ *+ * \param old_graph The original graph.+ * \param new_graph The new graph will be stored here.+ * \param corr A scalar in the unit interval, the target Pearson+ *        correlation between the adjacency matrices of the original the+ *        generated graph (the adjacency matrix being used as a vector).+ * \param p A numeric scalar, the probability of an edge between two+ *        vertices, it must in the open (0,1) interval.+ * \param permutation A permutation to apply to the vertices of the+ *        generated graph. It can also be a null pointer, in which case+ *        the vertices will not be permuted.+ * \return Error code+ *+ * \sa \ref igraph_correlated_pair_game() for generating a pair+ * of correlated random graphs in one go.+ */++int igraph_correlated_game(const igraph_t *old_graph, igraph_t *new_graph,+                           igraph_real_t corr, igraph_real_t p,+                           const igraph_vector_t *permutation) {++    int no_of_nodes = igraph_vcount(old_graph);+    int no_of_edges = igraph_ecount(old_graph);+    igraph_bool_t directed = igraph_is_directed(old_graph);+    igraph_real_t no_of_all = directed ? no_of_nodes * (no_of_nodes - 1) :+                              no_of_nodes * (no_of_nodes - 1) / 2;+    igraph_real_t no_of_missing = no_of_all - no_of_edges;+    igraph_real_t q = p + corr * (1 - p);+    igraph_real_t p_del = 1 - q;+    igraph_real_t p_add = ((1 - q) * (p / (1 - p)));+    igraph_vector_t add, delete, edges, newedges;+    igraph_real_t last;+    int p_e = 0, p_a = 0, p_d = 0, no_add, no_del;+    igraph_real_t inf = IGRAPH_INFINITY;+    igraph_real_t next_e, next_a, next_d;+    int i;++    if (corr < -1 || corr > 1) {+        IGRAPH_ERROR("Correlation must be in [-1,1] in correlated "+                     "Erdos-Renyi game", IGRAPH_EINVAL);+    }+    if (p <= 0 || p >= 1) {+        IGRAPH_ERROR("Edge probability must be in (0,1) in correlated "+                     "Erdos-Renyi game", IGRAPH_EINVAL);+    }+    if (permutation) {+        if (igraph_vector_size(permutation) != no_of_nodes) {+            IGRAPH_ERROR("Invalid permutation length in correlated Erdos-Renyi game",+                         IGRAPH_EINVAL);+        }+    }++    /* Special cases */++    if (corr == 0) {+        return igraph_erdos_renyi_game(new_graph, IGRAPH_ERDOS_RENYI_GNP,+                                       no_of_nodes, p, directed,+                                       IGRAPH_NO_LOOPS);+    }+    if (corr == 1) {+        /* We don't copy, because we don't need the attributes.... */+        IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges * 2);+        IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ 0));+        if (permutation) {+            int newec = igraph_vector_size(&edges);+            for (i = 0; i < newec; i++) {+                int tmp = VECTOR(edges)[i];+                VECTOR(edges)[i] = VECTOR(*permutation)[tmp];+            }+        }+        IGRAPH_CHECK(igraph_create(new_graph, &edges, no_of_nodes, directed));+        igraph_vector_destroy(&edges);+        IGRAPH_FINALLY_CLEAN(1);+        return 0;+    }++    IGRAPH_VECTOR_INIT_FINALLY(&newedges, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&add, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&delete, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&edges, no_of_edges * 2);++    IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ 0));++    RNG_BEGIN();++    if (p_del > 0) {+        last = RNG_GEOM(p_del);+        while (last < no_of_edges) {+            IGRAPH_CHECK(igraph_vector_push_back(&delete, last));+            last += RNG_GEOM(p_del);+            last += 1;+        }+    }+    no_del = igraph_vector_size(&delete);++    if (p_add > 0) {+        last = RNG_GEOM(p_add);+        while (last < no_of_missing) {+            IGRAPH_CHECK(igraph_vector_push_back(&add, last));+            last += RNG_GEOM(p_add);+            last += 1;+        }+    }+    no_add = igraph_vector_size(&add);++    RNG_END();++    IGRAPH_CHECK(igraph_get_edgelist(old_graph, &edges, /* bycol= */ 0));++    /* Now we are merging the original edges, the edges that are removed,+       and the new edges. We have the following pointers:+       - p_a: the next edge to add+       - p_d: the next edge to delete+       - p_e: the next original edge+       - next_e: the code of the next edge in 'edges'+       - next_a: the code of the next edge to add+       - next_d: the code of the next edge to delete */++#define D_CODE(f,t) (((t)==no_of_nodes-1 ? f : t) * no_of_nodes + (f))+#define U_CODE(f,t) ((t) * ((t)-1) / 2 + (f))+#define CODE(f,t) (directed ? D_CODE(f,t) : U_CODE(f,t))+#define CODEE() (CODE(VECTOR(edges)[2*p_e], VECTOR(edges)[2*p_e+1]))++    /* First we (re)code the edges to delete */++    for (i = 0; i < no_del; i++) {+        int td = VECTOR(delete)[i];+        int from = VECTOR(edges)[2 * td];+        int to = VECTOR(edges)[2 * td + 1];+        VECTOR(delete)[i] = CODE(from, to);+    }++    IGRAPH_CHECK(igraph_vector_reserve(&newedges,+                                       (no_of_edges - no_del + no_add) * 2));++    /* Now we can do the merge. Additional edges are tricky, because+       the code must be shifted by the edges in the original graph. */++#define UPD_E()                             \+    { if (p_e < no_of_edges) { next_e=CODEE(); } else { next_e = inf; } }+#define UPD_A()                             \+{ if (p_a < no_add) { \+            next_a = VECTOR(add)[p_a] + p_e; } else { next_a = inf; } }+#define UPD_D()                             \+{ if (p_d < no_del) { \+            next_d = VECTOR(delete)[p_d]; } else { next_d = inf; } }++    UPD_E(); UPD_A(); UPD_D();++    while (next_e != inf || next_a != inf || next_d != inf) {+        if (next_e <= next_a && next_e < next_d) {++            /* keep an edge */+            IGRAPH_CHECK(igraph_vector_push_back(&newedges, VECTOR(edges)[2 * p_e]));+            IGRAPH_CHECK(igraph_vector_push_back(&newedges, VECTOR(edges)[2 * p_e + 1]));+            p_e ++; UPD_E(); UPD_A()++        } else if (next_e <= next_a && next_e == next_d) {++            /* delete an edge */+            p_e ++; UPD_E(); UPD_A();+            p_d++; UPD_D();++        } else {++            /* add an edge */+            int to, from;+            if (directed) {+                to = (int) floor(next_a / no_of_nodes);+                from = (int) (next_a - ((igraph_real_t)to) * no_of_nodes);+                if (from == to) {+                    to = no_of_nodes - 1;+                }+            } else {+                to = (int) floor((sqrt(8 * next_a + 1) + 1) / 2);+                from = (int) (next_a - (((igraph_real_t)to) * (to - 1)) / 2);+            }+            IGRAPH_CHECK(igraph_vector_push_back(&newedges, from));+            IGRAPH_CHECK(igraph_vector_push_back(&newedges, to));+            p_a++; UPD_A();++        }+    }++    igraph_vector_destroy(&edges);+    igraph_vector_destroy(&add);+    igraph_vector_destroy(&delete);+    IGRAPH_FINALLY_CLEAN(3);++    if (permutation) {+        int newec = igraph_vector_size(&newedges);+        for (i = 0; i < newec; i++) {+            int tmp = VECTOR(newedges)[i];+            VECTOR(newedges)[i] = VECTOR(*permutation)[tmp];+        }+    }++    IGRAPH_CHECK(igraph_create(new_graph, &newedges, no_of_nodes, directed));++    igraph_vector_destroy(&newedges);+    IGRAPH_FINALLY_CLEAN(1);++    return 0;+}++#undef D_CODE+#undef U_CODE+#undef CODE+#undef CODEE+#undef UPD_E+#undef UPD_A+#undef UPD_D++/**+ * \function igraph_correlated_pair_game+ * Generate pairs of correlated random graphs+ *+ * Sample two random graphs, with given correlation.+ *+ * \param graph1 The first graph will be stored here.+ * \param graph2 The second graph will be stored here.+ * \param n The number of vertices in both graphs.+ * \param corr A scalar in the unit interval, the target Pearson+ *        correlation between the adjacency matrices of the original the+ *        generated graph (the adjacency matrix being used as a vector).+ * \param p A numeric scalar, the probability of an edge between two+ *        vertices, it must in the open (0,1) interval.+ * \param directed Whether to generate directed graphs.+ * \param permutation A permutation to apply to the vertices of the+ *        second graph. It can also be a null pointer, in which case+ *        the vertices will not be permuted.+ * \return Error code+ *+ * \sa \ref igraph_correlated_game() for generating a correlated pair+ * to a given graph.+ */++int igraph_correlated_pair_game(igraph_t *graph1, igraph_t *graph2,+                                int n, igraph_real_t corr, igraph_real_t p,+                                igraph_bool_t directed,+                                const igraph_vector_t *permutation) {++    IGRAPH_CHECK(igraph_erdos_renyi_game(graph1, IGRAPH_ERDOS_RENYI_GNP, n, p,+                                         directed, IGRAPH_NO_LOOPS));+    IGRAPH_CHECK(igraph_correlated_game(graph1, graph2, corr, p, permutation));+    return 0;+}+++/* Uniform sampling of labelled trees (igraph_tree_game) */++/* The following implementation uniformly samples Prufer trees and converts+ * them to trees.+ */++static int igraph_i_tree_game_prufer(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed) {+    igraph_vector_int_t prufer;+    long i;++    if (directed) {+        IGRAPH_ERROR("The Prufer method for random tree generation does not support directed trees", IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_vector_int_init(&prufer, n - 2));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &prufer);++    RNG_BEGIN();++    for (i = 0; i < n - 2; ++i) {+        VECTOR(prufer)[i] = RNG_INTEGER(0, n - 1);+    }++    RNG_END();++    IGRAPH_CHECK(igraph_from_prufer(graph, &prufer));++    igraph_vector_int_destroy(&prufer);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}++/* The following implementation is based on loop-erased random walks and Wilson's algorithm+ * for uniformly sampling spanning trees. We effectively sample spanning trees of the complete+ * graph.+ */++/* swap two elements of a vector_int */+#define SWAP_INT_ELEM(vec, i, j) \+    { \+        igraph_integer_t temp; \+        temp = VECTOR(vec)[i]; \+        VECTOR(vec)[i] = VECTOR(vec)[j]; \+        VECTOR(vec)[j] = temp; \+    }++static int igraph_i_tree_game_loop_erased_random_walk(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed) {+    igraph_vector_t edges;+    igraph_vector_int_t vertices;+    igraph_vector_bool_t visited;+    long i, j, k;++    IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * (n - 1));++    IGRAPH_CHECK(igraph_vector_bool_init(&visited, n));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &visited);++    /* The vertices vector contains visited vertices between 0..k-1, unvisited ones between k..n-1. */+    IGRAPH_CHECK(igraph_vector_int_init_seq(&vertices, 0, n - 1));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &vertices);++    RNG_BEGIN();++    /* A simple implementation could be as below. This is for illustration only.+     * The actually implemented algorithm avoids unnecessary walking on the already visited+     * portion of the vertex set.+     */+    /*+    // pick starting point for the walk+    i = RNG_INTEGER(0, n-1);+    VECTOR(visited)[i] = 1;++    k=1;+    while (k < n) {+        // pick next vertex in the walk+        j = RNG_INTEGER(0, n-1);+        // if it has not been visited before, connect to the previous vertex in the sequence+        if (! VECTOR(visited)[j]) {+            VECTOR(edges)[2*k - 2] = i;+            VECTOR(edges)[2*k - 1] = j;+            VECTOR(visited)[j] = 1;+            k++;+        }+        i=j;+    }+    */++    i = RNG_INTEGER(0, n - 1);+    VECTOR(visited)[i] = 1;+    SWAP_INT_ELEM(vertices, 0, i);++    for (k = 1; k < n; ++k) {+        j = RNG_INTEGER(0, n - 1);+        if (VECTOR(visited)[VECTOR(vertices)[j]]) {+            i = VECTOR(vertices)[j];+            j = RNG_INTEGER(k, n - 1);+        }+        VECTOR(visited)[VECTOR(vertices)[j]] = 1;+        SWAP_INT_ELEM(vertices, k, j);+        VECTOR(edges)[2 * k - 2] = i;+        i = VECTOR(vertices)[k];+        VECTOR(edges)[2 * k - 1] = i;+    }++    RNG_END();++    IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));++    igraph_vector_int_destroy(&vertices);+    igraph_vector_bool_destroy(&visited);+    igraph_vector_destroy(&edges);+    IGRAPH_FINALLY_CLEAN(3);++    return IGRAPH_SUCCESS;+}++#undef SWAP_INT_ELEM++/**+ * \ingroup generators+ * \function igraph_tree_game+ * \brief Generates a random tree with the given number of nodes+ *+ * This function samples uniformly from the set of labelled trees,+ * i.e. it can generate each labelled tree with the same probability.+ *+ * \param graph Pointer to an uninitialized graph object.+ * \param n The number of nodes in the tree.+ * \param directed Whether to create a directed tree. The edges are oriented away from the root.+ * \param method The algorithm to use to generate the tree. Possible values:+ *        \clist+ *        \cli IGRAPH_RANDOM_TREE_PRUFER+ *          This algorithm samples Pr&uuml;fer sequences unformly, then converts them to trees.+ *          Directed trees are not currently supported.+ *        \cli IGRAPH_RANDOM_LERW+ *          This algorithm effectively performs a loop-erased random walk on the complete graph+ *          to uniformly sample its spanning trees (Wilson's algorithm).+ *        \endclist+ * \return Error code:+ *          \c IGRAPH_ENOMEM: there is not enough+ *           memory to perform the operation.+ *          \c IGRAPH_EINVAL: invalid tree size+ *+ * \sa \ref igraph_from_prufer()+ *+ */++int igraph_tree_game(igraph_t *graph, igraph_integer_t n, igraph_bool_t directed, igraph_random_tree_t method) {+    if (n < 2) {+        IGRAPH_CHECK(igraph_empty(graph, n, directed));+        return IGRAPH_SUCCESS;+    }++    switch (method) {+    case IGRAPH_RANDOM_TREE_PRUFER:+        return igraph_i_tree_game_prufer(graph, n, directed);+    case IGRAPH_RANDOM_TREE_LERW:+        return igraph_i_tree_game_loop_erased_random_walk(graph, n, directed);+    default:+        IGRAPH_ERROR("Invalid method for random tree construction", IGRAPH_EINVAL);+    }+}
+ igraph/src/gengraph_box_list.cpp view
@@ -0,0 +1,108 @@+/*+ *+ * 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
+ igraph/src/gengraph_degree_sequence.cpp view
@@ -0,0 +1,420 @@+/*+ *+ * 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
+ igraph/src/gengraph_graph_molloy_hash.cpp view
@@ -0,0 +1,1173 @@+/*+ *+ * 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);+}++int64_t graph_molloy_hash::slow_connected_shuffle(int64_t times) {+  assert(verify());+  int64_t 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
+ igraph/src/gengraph_graph_molloy_optimized.cpp view
@@ -0,0 +1,2221 @@+/*+ *+ * 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"++#ifndef register+    #define register+#endif++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) ******++int64_t *graph_molloy_opt::vertex_betweenness_usp(bool trivial_paths) {+  if(VERBOSE()) fprintf(stderr,"Computing vertex betweenness USP...");+  int i;+  unsigned char *dist = new unsigned char[n];+  int *buff = new int[n];+  int64_t *b = new int64_t[n];+  int *bb = new int[n];+  int *dd = new int[max_degree()];+  for(i=0; i<n; i++) b[i]=0;+  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]]+=(int64_t)(bb[buff[i]]);+  }+  delete[] dist;+  delete[] buff;+  delete[] bb;+  delete[] dd;+  return b;+}++int64_t *graph_molloy_opt::vertex_betweenness_rsp(bool trivial_paths) {+  if(VERBOSE()) fprintf(stderr,"Computing vertex betweenness RSP...");+  int i;+  unsigned char *dist = new unsigned char[n];+  int *buff = new int[n];+  int64_t *b = new int64_t[n];+  int *bb = new int[n];+  int *dd = new int[max_degree()];+  for(i=0; i<n; i++) b[i]=0;+  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]]+=(int64_t)(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
+ igraph/src/gengraph_mr-connected.cpp view
@@ -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;+    }++}
+ igraph/src/gengraph_powerlaw.cpp view
@@ -0,0 +1,270 @@+/*+ *+ * 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
+ igraph/src/gengraph_random.cpp view
@@ -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+
+ igraph/src/getenv_.c view
@@ -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
+ igraph/src/glet.c view
@@ -0,0 +1,870 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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+ * in the thresholded input graph. In the second step,+ * the graph is projected onto the candidate basis, resulting in a+ * weight coefficient for each clique in the candidate basis.+ * </para>+ *+ * <para>+ * For more information on graphlet decomposition, see+ * Hossein Azari Soufiani and Edoardo M Airoldi: "Graphlet decomposition of a weighted network",+ * https://arxiv.org/abs/1203.2821 and http://proceedings.mlr.press/v22/azari12/azari12.pdf+ * </para>+ *+ * <para>+ * igraph contains three functions for performing the graphlet+ * decomponsition of a graph. The first is \ref igraph_graphlets(), which+ * performs both steps of the method and returns a list of subgraphs+ * with their corresponding weights. The other two 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>+ *+ * <para>+ * <remark>+ * Note: The term "graphlet" is used for several unrelated concepts+ * in the literature. If you are looking to count induced subgraphs, see+ * \ref igraph_motifs_randesu() and \ref igraph_subisomorphic_lad().+ * </remark>+ * </para>+ */++typedef struct {+    igraph_vector_int_t *resultids;+    igraph_t *result;+    igraph_vector_t *resultweights;+    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->resultids) {+        for (i = 0; i < data->nc; i++) {+            if (data->resultids + i) {+                igraph_vector_int_destroy(data->resultids + i);+            }+        }+        igraph_Free(data->resultids);+    }+    if (data->result) {+        for (i = 0; i < data->nc; i++) {+            if (data->result + i) {+                igraph_destroy(data->result + i);+            }+        }+        igraph_Free(data->result);+    }+    if (data->resultweights) {+        for (i = 0; i < data->nc; i++) {+            if (data->resultweights + i) {+                igraph_vector_destroy(data->resultweights + i);+            }+        }+        igraph_Free(data->resultweights);+    }+}++/**+ * \function igraph_i_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_i_subclique_next(const igraph_t *graph,+                            const igraph_vector_t *weights,+                            const igraph_vector_int_t *ids,+                            const igraph_vector_ptr_t *cliques,+                            igraph_t **result,+                            igraph_vector_t **resultweights,+                            igraph_vector_int_t **resultids,+                            igraph_vector_t *clique_thr,+                            igraph_vector_t *next_thr) {++    /* The input is a set of cliques, that were found at a previous level.+       For each clique, we calculate the next threshold, drop the isolate+       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_i_subclique_next_free_t freedata = { 0, 0, 0, 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);+    }++    IGRAPH_FINALLY(igraph_i_subclique_next_free, &freedata);+    *resultids = igraph_Calloc(nc, igraph_vector_int_t);+    if (!*resultids) {+        IGRAPH_ERROR("Cannot calculate next cliques", IGRAPH_ENOMEM);+    }+    freedata.resultids = *resultids;+    *resultweights = igraph_Calloc(nc, igraph_vector_t);+    if (!*resultweights) {+        IGRAPH_ERROR("Cannot calculate next cliques", IGRAPH_ENOMEM);+    }+    freedata.resultweights = *resultweights;+    *result = igraph_Calloc(nc, igraph_t);+    if (!*result) {+        IGRAPH_ERROR("Cannot calculate next cliques", IGRAPH_ENOMEM);+    }+    freedata.result = *result;++    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 = (*resultids) + c;+        igraph_vector_t *neww = (*resultweights) + c;+        igraph_t *newgraph = (*result) + 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);+        igraph_vector_init(neww, 0);++        /* 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);++        /* --------------------------------------------------- */++    } /* 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);  /* + freedata */++    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);+}++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_t *newgraphs = 0;+    igraph_vector_t *newweights = 0;+    igraph_vector_int_t *newids = 0;+    igraph_vector_t clique_thr, next_thr;+    igraph_i_subclique_next_free_t freedata = { 0, 0, 0, 0 };++    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_FINALLY(igraph_destroy, &subg);+    igraph_maximal_cliques(&subg, &mycliques, /*min_size=*/ 0, /*max_size=*/ 0);+    igraph_destroy(&subg);+    IGRAPH_FINALLY_CLEAN(1);+    nocliques = igraph_vector_ptr_size(&mycliques);++    igraph_vector_destroy(&subv);+    IGRAPH_FINALLY_CLEAN(1);++    /* Get the next cliques and thresholds */+    IGRAPH_VECTOR_INIT_FINALLY(&next_thr, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&clique_thr, 0);++    igraph_i_subclique_next(graph, weights, ids, &mycliques,+                            &newgraphs, &newweights, &newids,+                            &clique_thr, &next_thr);++    freedata.result = newgraphs;+    freedata.resultids = newids;+    freedata.resultweights = newweights;+    freedata.nc = nocliques;+    IGRAPH_FINALLY(igraph_i_subclique_next_free, &freedata);++    /* 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(&mycliques);+    for (i = 0; i < nographs; i++) {+        igraph_t *g = newgraphs + i;+        if (igraph_vcount(g) > 1) {+            igraph_vector_t *w = newweights + i;+            igraph_vector_int_t *ids = 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_subclique_next_free(&freedata);+    igraph_vector_ptr_destroy(&mycliques); /* contents was copied over */+    IGRAPH_FINALLY_CLEAN(4);++    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);+                igraph_free(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. Each elements must be+ *        destroyed using \ref igraph_vector_destroy() and \ref igraph_free().+ * \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 (weights == NULL) {+        IGRAPH_ERROR("Graphlet functions require weighted graphs", IGRAPH_EINVAL);+    }++    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 (weights == NULL) {+        IGRAPH_ERROR("Graphlet functions require weighted graphs", IGRAPH_EINVAL);+    }+    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_CHECK(igraph_vector_int_init(&vclidx, no_of_nodes + 2));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &vclidx);+    IGRAPH_CHECK(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_of_nodes; i++) {+        VECTOR(vclidx)[i + 2] += VECTOR(vclidx)[i + 1];+    }++    /* Create vertex-clique list, the cliques for each vertex. */+    IGRAPH_CHECK(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_CHECK(igraph_vector_int_init(&ecl, total_edges));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &ecl);+    IGRAPH_CHECK(igraph_vector_int_init(&eclidx, no_of_edges + 1));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &eclidx);+    IGRAPH_CHECK(igraph_vector_init(&edgelist, no_of_edges * 2));+    IGRAPH_FINALLY(igraph_vector_destroy, &edgelist);+    IGRAPH_CHECK(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_CHECK(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_CHECK(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_CHECK(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;+}
+ igraph/src/glpk_support.c view
@@ -0,0 +1,101 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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(info);++    /* This is a special version of IGRAPH_ALLOW_INTERRUPTION().+       Calling glp_ios_terminate() from glp_intopt()'s callback function+       signals to GLPK that it should terminate the optimization and return+       with the code GLP_ESTOP.+    */+    if (igraph_i_interruption_handler) {+        if (igraph_allow_interruption(NULL) != IGRAPH_SUCCESS) {+            glp_ios_terminate(tree);+        }+    }+}++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;+#define HANDLE_CODE3(c) case c: code = #c; retval = IGRAPH_INTERRUPTED; 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_CODE3(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+#undef HANDLE_CODE2+#undef HANDLE_CODE3++    sprintf(message_and_code, "%s (%s)", message, code);+    IGRAPH_ERROR(message_and_code, retval);+}++#endif++#ifdef USING_R++int igraph_glpk_dummy() {+    return 'b' + 'a' + 's' + 's' + 'z' + 'a' + 't' + 'o' + 'k' ++           'm' + 'e' + 'g';+}++#endif
+ igraph/src/gml_tree.c view
@@ -0,0 +1,261 @@+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/graph.cc view
@@ -0,0 +1,5609 @@+#include <cstdio>+#include <cassert>+#include <climits>+#include <set>+#include <list>+#include <algorithm>++#include "defs.hh"+#include "graph.hh"+#include "partition.hh"+#include "utils.hh"++/* use 'and' instead of '&&' */+#if _MSC_VER+#include <ciso646>+#endif++#ifdef USING_R+#undef stdout+#define stdout NULL+#endif++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/+++namespace bliss {++#define _INTERNAL_ERROR() fatal_error("%s:%d: internal error",__FILE__,__LINE__)+#define _OUT_OF_MEMORY() fatal_error("%s:%d: out of memory",__FILE__,__LINE__)++/*-------------------------------------------------------------------------+ *+ * 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;+  in_search = false;++  /* Default value for using "long prune" */+  opt_use_long_prune = true;+  /* Default value for using failure recording */+  opt_use_failure_recording = true;+  /* Default value for using component recursion */+  opt_use_comprec = true;+++  verbose_level = 0;+  verbstr = stdout;++  report_hook = 0;+  report_user_param = 0;+}+++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; }+ +  report_hook = 0;+  report_user_param = 0;+}++++/*-------------------------------------------------------------------------+ *+ * Verbose output management routines+ *+ *-------------------------------------------------------------------------*/++void+AbstractGraph::set_verbose_level(const unsigned int level)+{+  verbose_level = level;+}++void+AbstractGraph::set_verbose_file(FILE* const fp)+{+  verbstr = fp;+}++++/*-------------------------------------------------------------------------+ *+ * Routines for refinement to equitable partition+ *+ *-------------------------------------------------------------------------*/++void+AbstractGraph::refine_to_equitable()+{++  /* Start refinement from all cells -> push 'em all in the splitting queue */+  for(Partition::Cell* cell = p.first_cell; cell; cell = cell->next)+    p.splitting_queue_add(cell);++  do_refine_to_equitable();++}++void+AbstractGraph::refine_to_equitable(Partition::Cell* const unit_cell)+{++  p.splitting_queue_add(unit_cell);++  do_refine_to_equitable();+}++++void+AbstractGraph::refine_to_equitable(Partition::Cell* const unit_cell1,+				   Partition::Cell* const unit_cell2)+{++  p.splitting_queue_add(unit_cell1);+  p.splitting_queue_add(unit_cell2);++  do_refine_to_equitable();+}++++bool+AbstractGraph::do_refine_to_equitable()+{++  eqref_hash.reset();++  while(!p.splitting_queue_is_empty())+    {+      Partition::Cell* const cell = p.splitting_queue_pop();++      if(cell->is_unit())+	{+	  if(in_search) {+	    const unsigned int index = cell->first;+	    if(first_path_automorphism)+	      {+		/* Build the (potential) automorphism on-the-fly */+		first_path_automorphism[first_path_labeling_inv[index]] =+		  p.elements[index];+	      }+	    if(best_path_automorphism)+	      {+		/* Build the (potential) automorphism on-the-fly */+		best_path_automorphism[best_path_labeling_inv[index]] =+		  p.elements[index];+	      }+	  }+	  const bool worse = split_neighbourhood_of_unit_cell(cell);+	  if(in_search and worse)+	    goto worse_exit;+	}+      else+	{+	  const bool worse = split_neighbourhood_of_cell(cell);+	  if(in_search and worse)+	    goto worse_exit;+	}+    }++  return true;++ worse_exit:+  /* Clear splitting_queue */+  p.splitting_queue_clear();+  return false;+}+++++++++++++++++/*-------------------------------------------------------------------------+ *+ * Routines for handling the canonical labeling+ *+ *-------------------------------------------------------------------------*/++/** \internal+ * Assign the labeling induced by the current partition 'this.p' to+ * \a labeling.+ * That is, if the partition is [[2,0],[1]],+ * then \a labeling will map 0 to 1, 1 to 2, and 2 to 0.+ */+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;+}++/** \internal+ * The same as update_labeling() except that the inverse of the labeling+ * is also produced and assigned to \a labeling_inv.+ */+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+ *+ *-------------------------------------------------------------------------*/+++/** \internal+ * Reset the permutation \a perm to the identity permutation.+ */+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)+{+  _INTERNAL_ERROR();+  return false;+}++bool+AbstractGraph::is_automorphism(const std::vector<unsigned int>& perm) const+{+  _INTERNAL_ERROR();+  return false;+}+++++/*-------------------------------------------------------------------------+ *+ * Certificate building+ *+ *-------------------------------------------------------------------------*/++void+AbstractGraph::cert_add(const unsigned int v1,+			const unsigned int v2,+			const unsigned int v3)+{+  if(refine_compare_certificate)+    {+      if(refine_equal_to_first)+	{+	  /* So far equivalent to the first path... */+	  unsigned int index = certificate_current_path.size();+	  if(index >= refine_first_path_subcertificate_end)+	    {+	      refine_equal_to_first = false;+	    }+	  else if(certificate_first_path[index] != v1)+	    {+	      refine_equal_to_first = false;+	    }+	  else if(certificate_first_path[++index] != v2)+	    {+	      refine_equal_to_first = false;+	    }+	  else if(certificate_first_path[++index] != v3)+	    {+	      refine_equal_to_first = false;+	    }+	  if(opt_use_failure_recording and !refine_equal_to_first)+	    {+	      /* We just became different from the first path,+	       * remember the deviation point tree-specific invariant+	       * for the use of failure recording */+	      UintSeqHash h;+	      h.update(v1);+	      h.update(v2);+	      h.update(v3);+	      h.update(index);+	      h.update(eqref_hash.get_value());+	      failure_recording_fp_deviation = h.get_value();+	    }+	}+      if(refine_cmp_to_best == 0)+	{+	  /* So far equivalent to the current best path... */+	  unsigned int index = certificate_current_path.size();+	  if(index >= refine_best_path_subcertificate_end)+	    {+	      refine_cmp_to_best = 1;+	    }+	  else if(v1 > certificate_best_path[index])+	    {+	      refine_cmp_to_best = 1;+	    }+	  else if(v1 < certificate_best_path[index])+	    {+	      refine_cmp_to_best = -1;+	    }+	  else if(v2 > certificate_best_path[++index])+	    {+	      refine_cmp_to_best = 1;+	    }+	  else if(v2 < certificate_best_path[index])+	    {+	      refine_cmp_to_best = -1;+	    }+	  else if(v3 > certificate_best_path[++index])+	    {+	      refine_cmp_to_best = 1;+	    }+	  else if(v3 < certificate_best_path[index])+	    {+	      refine_cmp_to_best = -1;+	    }+	}+      if((refine_equal_to_first == false) and+	 (refine_cmp_to_best < 0))+	return;+    }+  /* Update the current path certificate */+  certificate_current_path.push_back(v1);+  certificate_current_path.push_back(v2);+  certificate_current_path.push_back(v3);+}+++void+AbstractGraph::cert_add_redundant(const unsigned int v1,+				  const unsigned int v2,+				  const unsigned int v3)+{+  return cert_add(v1, v2, v3);+}++++++++++++/*-------------------------------------------------------------------------+ *+ * Long prune code+ *+ *-------------------------------------------------------------------------*/++void+AbstractGraph::long_prune_init()+{+  const unsigned int N = get_nof_vertices();+  long_prune_temp.clear();+  long_prune_temp.resize(N);+  /* Of how many automorphisms we can store information in+     the predefined, fixed amount of memory? */+  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;++  long_prune_deallocate();+  long_prune_fixed.resize(N, 0);+  long_prune_mcrs.resize(N, 0);+  long_prune_begin = 0;+  long_prune_end = 0;+}++void+AbstractGraph::long_prune_deallocate()+{+  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();+    }+}++void+AbstractGraph::long_prune_swap(const unsigned int i, const unsigned int j)+{+  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_allocget_fixed(const unsigned int index)+{+  const unsigned int i = index % long_prune_max_stored_autss;+  if(!long_prune_fixed[i])+    long_prune_fixed[i] = new std::vector<bool>(get_nof_vertices());+  return *long_prune_fixed[i];+}++std::vector<bool>&+AbstractGraph::long_prune_get_fixed(const unsigned int index)+{+  return *long_prune_fixed[index % long_prune_max_stored_autss];+}++std::vector<bool>&+AbstractGraph::long_prune_allocget_mcrs(const unsigned int index)+{+  const unsigned int i = index % long_prune_max_stored_autss;+  if(!long_prune_mcrs[i])+    long_prune_mcrs[i] = new std::vector<bool>(get_nof_vertices());+  return *long_prune_mcrs[i];+}++std::vector<bool>&+AbstractGraph::long_prune_get_mcrs(const unsigned int index)+{+  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();+++  /* If the buffer of stored auts is full, remove the oldest aut */+  if(long_prune_end - long_prune_begin == long_prune_max_stored_autss)+    {+      long_prune_begin++;+    }+  long_prune_end++;+  std::vector<bool>& fixed = long_prune_allocget_fixed(long_prune_end-1);+  std::vector<bool>& mcrs = long_prune_allocget_mcrs(long_prune_end-1);+  /* Mark nodes that are (i) fixed or (ii) minimal orbit representatives+   * under the automorphism 'aut' */+  for(unsigned int i = 0; i < N; i++)+    {+      fixed[i] = (aut[i] == i);+      if(long_prune_temp[i] == false)+	{+	  mcrs[i] = true;+	  unsigned int j = aut[i];+	  while(j != i)+	    {+	      long_prune_temp[j] = true;+	      j = aut[j];+	    }+	}+      else+	{+	  mcrs[i] = false;+	}+      /* Clear the temp array on-the-fly... */+      long_prune_temp[i] = false;+    }+++}++++/*-------------------------------------------------------------------------+ *+ * Routines for handling orbit information+ *+ *-------------------------------------------------------------------------*/++void+AbstractGraph::update_orbit_information(Orbit& o, const unsigned int* perm)+{+  const unsigned int N = get_nof_vertices();+  for(unsigned int i = 0; i < N; i++)+    if(perm[i] != i)+      o.merge_orbits(i, perm[i]);+}+++++++++/*-------------------------------------------------------------------------+ *+ * The actual backtracking search+ *+ *-------------------------------------------------------------------------*/++class TreeNode+{+  //friend class AbstractGraph;+public:+  unsigned int split_cell_first;++  int split_element;+  static const int SPLIT_START = -1;+  static const int SPLIT_END   = -2;++  Partition::BacktrackPoint partition_bt_point;++  unsigned int certificate_index;++  static const char NO = -1;+  static const char MAYBE = 0;+  static const char YES = 1;++  /* First path stuff */+  bool fp_on;+  bool fp_cert_equal;+  char fp_extendable;++  /* Best path stuff */+  bool in_best_path;+  int cmp_to_best_path;++  unsigned int failure_recording_ival;++  /* Component recursion related data */+  unsigned int cr_cep_stack_size;+  unsigned int cr_cep_index;+  unsigned int cr_level;++  bool needs_long_prune;+  unsigned int long_prune_begin;+  std::set<unsigned int, std::less<unsigned int> > long_prune_redundant;+  +  UintSeqHash eqref_hash;+  unsigned int subcertificate_length;+};+++++typedef struct {+  unsigned int splitting_element;+  unsigned int certificate_index;+  unsigned int subcertificate_length;+  UintSeqHash eqref_hash;+} PathInfo;+++void+AbstractGraph::search(const bool canonical, Stats& stats)+{+  const unsigned int N = get_nof_vertices();++  unsigned int all_same_level = UINT_MAX;++  p.graph = this;++  /*+   * Must be done!+   */+  remove_duplicate_edges();++  /*+   * Reset search statistics+   */+  stats.reset();+  stats.nof_nodes = 1;+  stats.nof_leaf_nodes = 1;++  /* Free old first path data structures */+  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; }++  /* Free old best path data structures */+  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)+    {+      /* Nothing to do, return... */+      return;+    }++  /* Initialize the partition ... */+  p.init(N);+  /* ... and the component recursion data structures in the partition */+  if(opt_use_comprec)+    p.cr_init();+  +  neighbour_heap.init(N);++  in_search = false;+  /* Do not compute certificate when building the initial partition */+  refine_compare_certificate = false;+  /* The 'eqref_hash' hash value is not computed when building+   * the initial partition as it is not used for anything at the moment.+   * This saves some cycles. */+  compute_eqref_hash = false;++  make_initial_equitable_partition();++  /*+   * Allocate space for the "first path" and "best path" labelings+   */+  if(first_path_labeling) free(first_path_labeling);+  first_path_labeling = (unsigned int*)calloc(N, sizeof(unsigned int));+  if(!first_path_labeling) _OUT_OF_MEMORY();+  if(best_path_labeling) free(best_path_labeling);+  best_path_labeling = (unsigned int*)calloc(N, sizeof(unsigned int));+  if(!best_path_labeling) _OUT_OF_MEMORY();++  /*+   * Is the initial partition discrete?+   */+  if(p.is_discrete())+    {+      /* Make the best path labeling i.e. the canonical labeling */+      update_labeling(best_path_labeling);+      /* Update statistics */+      stats.nof_leaf_nodes = 1;+      /* Free component recursion data */+      if(opt_use_comprec)+        p.cr_free();+      return;+    }++  /*+   * Allocate the inverses of the "first path" and "best path" labelings+   */+  if(first_path_labeling_inv) free(first_path_labeling_inv);+  first_path_labeling_inv = (unsigned int*)calloc(N, sizeof(unsigned int));+  if(!first_path_labeling_inv) _OUT_OF_MEMORY();+  if(best_path_labeling_inv) free(best_path_labeling_inv);+  best_path_labeling_inv = (unsigned int*)calloc(N, sizeof(unsigned int));+  if(!best_path_labeling_inv) _OUT_OF_MEMORY();++  /*+   * Allocate space for the automorphisms+   */+  if(first_path_automorphism) free(first_path_automorphism);+  first_path_automorphism = (unsigned int*)malloc(N * sizeof(unsigned int));+  if(!first_path_automorphism) _OUT_OF_MEMORY();+  if(best_path_automorphism) free(best_path_automorphism);+  best_path_automorphism = (unsigned int*)malloc(N * sizeof(unsigned int));+  if(!best_path_automorphism) _OUT_OF_MEMORY();++  /*+   * Initialize orbit information so that all vertices are in their own orbits+   */+  first_path_orbits.init(N);+  best_path_orbits.init(N);++  /*+   * Initialize certificate memory+   */+  initialize_certificate();++  std::vector<TreeNode> search_stack;+  std::vector<PathInfo> first_path_info;+  std::vector<PathInfo> best_path_info;++  search_stack.clear();++  /* Initialize "long prune" data structures */+  if(opt_use_long_prune)+    long_prune_init();++  /*+   * Initialize failure recording data structures+   */+  typedef std::set<unsigned int, std::less<unsigned int> > FailureRecordingSet;+  std::vector<FailureRecordingSet> failure_recording_hashes;++  /*+   * Initialize component recursion data structures+   */+  cr_cep_stack.clear();+  unsigned int cr_cep_index = 0;+  {+    /* Inset a sentinel "component end point" */+    CR_CEP sentinel;+    sentinel.creation_level = 0;+    sentinel.discrete_cell_limit = get_nof_vertices();+    sentinel.next_cr_level = 0;+    sentinel.next_cep_index = 0;+    sentinel.first_checked = false;+    sentinel.best_checked = false;+    cr_cep_index = 0;+    cr_cep_stack.push_back(sentinel);+  }+  cr_level = 0;+  if(opt_use_comprec and+     nucr_find_first_component(cr_level) == true and+     p.nof_discrete_cells() + cr_component_elements < +     cr_cep_stack[cr_cep_index].discrete_cell_limit)+    {+      cr_level = p.cr_split_level(0, cr_component);+      CR_CEP cep;+      cep.creation_level = 0;+      cep.discrete_cell_limit = p.nof_discrete_cells() + cr_component_elements;+      cep.next_cr_level = 0;+      cep.next_cep_index = cr_cep_index;+      cep.first_checked = false;+      cep.best_checked = false;+      cr_cep_index = cr_cep_stack.size();+      cr_cep_stack.push_back(cep);+    }++  /*+   * Build the root node of the search tree+   */+  {+    TreeNode root;+    Partition::Cell* split_cell = find_next_cell_to_be_splitted(p.first_cell);+    root.split_cell_first = split_cell->first;+    root.split_element = TreeNode::SPLIT_START;+    root.partition_bt_point = p.set_backtrack_point();+    root.certificate_index = 0;+    root.fp_on = true;+    root.fp_cert_equal = true;+    root.fp_extendable = TreeNode::MAYBE;+    root.in_best_path = false;+    root.cmp_to_best_path = 0;+    root.long_prune_begin = 0;++    root.failure_recording_ival = 0;++    /* Save component recursion info for backtracking */+    root.cr_level = cr_level;+    root.cr_cep_stack_size = cr_cep_stack.size();+    root.cr_cep_index = cr_cep_index;+    search_stack.push_back(root);+  }++  /*+   * Set status and global flags for search related procedures+   */+  in_search = true;+  /* Do not compare certificates during refinement until the first path has been traversed to the leaf */+  refine_compare_certificate = false;+++++  /*+   * The actual backtracking search+   */+  while(!search_stack.empty()) +    {+      TreeNode&          current_node  = search_stack.back();+      const unsigned int current_level = (unsigned int)search_stack.size()-1;+++      if(opt_use_comprec)+	{+	  CR_CEP& cep = cr_cep_stack[current_node.cr_cep_index];+	  if(cep.first_checked == true and+	     current_node.fp_extendable == TreeNode::MAYBE and+	     !search_stack[cep.creation_level].fp_on)+	    {+	      current_node.fp_extendable = TreeNode::NO;+	    }+	}++      if(current_node.fp_on)+	{+	  if(current_node.split_element == TreeNode::SPLIT_END)+	    {+	      search_stack.pop_back();+	      continue;+	    }+	}+      else+	{+	  if(current_node.fp_extendable == TreeNode::YES)+	    {+	      search_stack.pop_back();+	      continue;	      +	    }+	  if(current_node.split_element == TreeNode::SPLIT_END)+	    {+	      if(opt_use_failure_recording)+		{+		  TreeNode& parent_node = search_stack[current_level-1];+		  if(parent_node.fp_on)+		    failure_recording_hashes[current_level-1].insert(current_node.failure_recording_ival);+		}+	      search_stack.pop_back();+	      continue;+	    }+	  if(current_node.fp_extendable == TreeNode::NO and+	     (!canonical or current_node.cmp_to_best_path < 0))+	    {+	      if(opt_use_failure_recording)+		{+		  TreeNode& parent_node = search_stack[current_level-1];+		  if(parent_node.fp_on)+		    failure_recording_hashes[current_level-1].insert(current_node.failure_recording_ival);+		}+	      search_stack.pop_back();+	      continue;+	    }+	}++      /* Restore partition ... */+      p.goto_backtrack_point(current_node.partition_bt_point);+      /* ... and re-remember backtracking point */+      current_node.partition_bt_point = p.set_backtrack_point();++      /* Restore current path certificate */+      certificate_index = current_node.certificate_index;+      refine_current_path_certificate_index = current_node.certificate_index;+      certificate_current_path.resize(certificate_index);++      /* Fetch split cell information */+      Partition::Cell * const cell =+	p.get_cell(p.elements[current_node.split_cell_first]);+  +      /* Restore component recursion information */+      cr_level = current_node.cr_level;+      cr_cep_stack.resize(current_node.cr_cep_stack_size);+      cr_cep_index = current_node.cr_cep_index;+++      /*+       * Update long prune redundancy sets+       */+      if(opt_use_long_prune and current_level >= 1 and !current_node.fp_on)+	{+	  unsigned int begin = (current_node.long_prune_begin>long_prune_begin)?current_node.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);+#if defined(BLISS_CONSISTENCY_CHECKS)+	      for(unsigned int l = 0; l < search_stack.size()-2; l++)+		assert(fixed[search_stack[l].split_element]);+#endif+	      if(fixed[search_stack[search_stack.size()-1-1].split_element] ==+		 false)+		{+		  long_prune_swap(begin, i);+		  begin++;+		  current_node.long_prune_begin = begin;+		  continue;+		}+	    }++	  if(current_node.split_element == TreeNode::SPLIT_START)+	    {+	      current_node.needs_long_prune = true;+	    }+	  else if(current_node.needs_long_prune)+	    {+	      current_node.needs_long_prune = false;+	      unsigned int begin = (current_node.long_prune_begin>long_prune_begin)?current_node.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);+#if defined(BLISS_CONSISTENCY_CHECKS)+		  for(unsigned int l = 0; l < search_stack.size()-2; l++)+		    assert(fixed[search_stack[l].split_element]);+#endif+		  assert(fixed[search_stack[current_level-1].split_element] == true);+		  if(fixed[search_stack[current_level-1].split_element] == false)+		    {+		      long_prune_swap(begin, i);+		      begin++;+		      current_node.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)+		      current_node.long_prune_redundant.insert(*ep);+		  }+		}+	    }+	}+++      /*+       * Find the next smallest, non-isomorphic element in the cell and+       * store it in current_node.split_element+       */+      {+	unsigned int  next_split_element = UINT_MAX;+	//unsigned int* next_split_element_pos = 0;+	unsigned int* ep = p.elements + cell->first;+	if(current_node.fp_on)+	  {+	    /* Find the next larger splitting element that is+	     * a minimal orbit representative w.r.t. first_path_orbits */+	    for(unsigned int i = cell->length; i > 0; i--, ep++) {+	      if((int)(*ep) > current_node.split_element and+		 *ep < next_split_element and+		 first_path_orbits.is_minimal_representative(*ep)) {+		next_split_element = *ep;+		//next_split_element_pos = ep;+	      }+	    }+	  }+	else if(current_node.in_best_path)+	  {+	    /* Find the next larger splitting element that is+	     * a minimal orbit representative w.r.t. best_path_orbits */+	    for(unsigned int i = cell->length; i > 0; i--, ep++) {+	      if((int)(*ep) > current_node.split_element and+		 *ep < next_split_element and+		 best_path_orbits.is_minimal_representative(*ep) and+		 (!opt_use_long_prune or+		  current_node.long_prune_redundant.find(*ep) ==+		  current_node.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) > current_node.split_element and+		 *ep < next_split_element and+		 (!opt_use_long_prune or+		  current_node.long_prune_redundant.find(*ep) ==+		  current_node.long_prune_redundant.end())) {+		next_split_element = *ep;+		//next_split_element_pos = ep;+	      }+	    }+	  }+	if(next_split_element == UINT_MAX)+	  {+	    /* No more (unexplored children) in the cell */+	    current_node.split_element = TreeNode::SPLIT_END;+	    if(current_node.fp_on)+	      {+		/* Update group size */+		const unsigned int index = first_path_orbits.orbit_size(first_path_info[search_stack.size()-1].splitting_element);+		stats.group_size.multiply(index);+		stats.group_size_approx *= (long double)index;+		/*+		 * Update all_same_level+		 */+		if(index == cell->length and all_same_level == current_level+1)+		  all_same_level = current_level;+		if(verbstr and verbose_level >= 2) {+		  fprintf(verbstr,+			  "Level %u: orbits=%u, index=%u/%u, all_same_level=%u\n",+			  current_level,+			  first_path_orbits.nof_orbits(),+			  index, cell->length,+			  all_same_level);+		  fflush(verbstr);+		}+	      }+	    continue;+	  }+	+	/* Split on smallest */+	current_node.split_element = next_split_element;+      }++      const unsigned int child_level = current_level+1;+      /* Update some statistics */+      stats.nof_nodes++;+      if(search_stack.size() > stats.max_level)+	stats.max_level = search_stack.size();++++      /* Set flags and indices for the refiner certificate builder */+      refine_equal_to_first = current_node.fp_cert_equal;+      refine_cmp_to_best = current_node.cmp_to_best_path;+      if(!first_path_info.empty())+	{+	  if(refine_equal_to_first)+	    refine_first_path_subcertificate_end =+	      first_path_info[search_stack.size()-1].certificate_index ++	      first_path_info[search_stack.size()-1].subcertificate_length;+	  if(canonical)+	    {+	      if(refine_cmp_to_best == 0)+		refine_best_path_subcertificate_end =+		  best_path_info[search_stack.size()-1].certificate_index ++		  best_path_info[search_stack.size()-1].subcertificate_length;+	    }+	  else+	    refine_cmp_to_best = -1;+	}++      const bool was_fp_cert_equal = current_node.fp_cert_equal;++      /* Individualize, i.e. split the cell in two, the latter new cell+       * will be a unit one containing info.split_element */+      Partition::Cell* const new_cell =+	p.individualize(cell, current_node.split_element);++      /*+       * Refine the new partition to equitable+       */+      if(cell->is_unit())+	refine_to_equitable(cell, new_cell);+      else +	refine_to_equitable(new_cell);+++++      /* Update statistics */+      if(p.is_discrete())+	stats.nof_leaf_nodes++;+++      if(!first_path_info.empty())+	{+	  /* We are no longer on the first path */+	  const unsigned int subcertificate_length = +	    certificate_current_path.size() - certificate_index;+	  if(refine_equal_to_first)+	    {+	      /* Was equal to the first path so far */+	      PathInfo& first_pinfo = first_path_info[current_level];+	      assert(first_pinfo.certificate_index == certificate_index);+	      if(subcertificate_length != first_pinfo.subcertificate_length)+		{+		  refine_equal_to_first = false;+		  if(opt_use_failure_recording)+		    failure_recording_fp_deviation = subcertificate_length;+		}+	      else if(first_pinfo.eqref_hash.cmp(eqref_hash) != 0)+		{+		  refine_equal_to_first = false;+		  if(opt_use_failure_recording)+		    failure_recording_fp_deviation = eqref_hash.get_value();+		}+	    }+	  if(canonical and (refine_cmp_to_best == 0))+	    {+	      /* Was equal to the best path so far */+	      PathInfo& bestp_info = best_path_info[current_level];+	      assert(bestp_info.certificate_index == certificate_index);+	      if(subcertificate_length < bestp_info.subcertificate_length)+		{+		  refine_cmp_to_best = -1;+		}+	      else if(subcertificate_length > bestp_info.subcertificate_length)+		{+		  refine_cmp_to_best = 1;+		}+	      else if(bestp_info.eqref_hash.cmp(eqref_hash) > 0)+		{+		  refine_cmp_to_best = -1;+		}+	      else if(bestp_info.eqref_hash.cmp(eqref_hash) < 0)+		{+		  refine_cmp_to_best = 1;+		}+	    }++	  if(opt_use_failure_recording and+	     was_fp_cert_equal and+	     !refine_equal_to_first)+	    {+	      UintSeqHash k;+	      k.update(failure_recording_fp_deviation);+	      k.update(eqref_hash.get_value());+	      failure_recording_fp_deviation = k.get_value();++	      if(current_node.fp_on)+		failure_recording_hashes[current_level].insert(failure_recording_fp_deviation);+	      else+		{+		  for(unsigned int i = current_level; i > 0; i--)+		    {+		      if(search_stack[i].fp_on)+			break;+		      const FailureRecordingSet& s = failure_recording_hashes[i];+		      if(i == current_level and+			 s.find(failure_recording_fp_deviation) != s.end())+			break;+		      if(s.find(0) != s.end())+			break;+		      search_stack[i].fp_extendable = TreeNode::NO;+		    }+		}+	    }++	  +	  /* Check if no longer equal to the first path and,+	   * if canonical labeling is desired, also worse than the+	   * current best path */+	  if(refine_equal_to_first == false and+	     (!canonical or (refine_cmp_to_best < 0)))+	    {+	      /* Yes, backtrack */+	      stats.nof_bad_nodes++;+	      if(current_node.fp_cert_equal == true and+		 current_level+1 > all_same_level)+		{+		  assert(all_same_level >= 1);+		  for(unsigned int i = all_same_level;+		      i < search_stack.size();+		      i++)+		    {+		      search_stack[i].fp_extendable = TreeNode::NO;+		    }+		}++	      continue;+	    }+	}++#if defined(BLISS_VERIFY_EQUITABLEDNESS)+      /* The new partition should be equitable */+      if(!is_equitable())+	fatal_error("consistency check failed - partition after refinement is not equitable");+#endif++      /*+       * Next level search tree node info+       */+      TreeNode child_node;++      /* No more in the first path */+      child_node.fp_on = false;+      /* No more in the best path */+      child_node.in_best_path = false;++      child_node.fp_cert_equal = refine_equal_to_first;+      if(current_node.fp_extendable == TreeNode::NO or+	 (current_node.fp_extendable == TreeNode::MAYBE and+	  child_node.fp_cert_equal == false))+	child_node.fp_extendable = TreeNode::NO;+      else+	child_node.fp_extendable = TreeNode::MAYBE;+      child_node.cmp_to_best_path = refine_cmp_to_best;++      child_node.failure_recording_ival = 0;+      child_node.cr_cep_stack_size = current_node.cr_cep_stack_size;+      child_node.cr_cep_index = current_node.cr_cep_index;+      child_node.cr_level = current_node.cr_level;++      certificate_index = certificate_current_path.size();++      current_node.eqref_hash = eqref_hash;+      current_node.subcertificate_length =+	certificate_index - current_node.certificate_index;+++      /*+       * The first encountered leaf node at the end of the "first path"?+       */+      if(p.is_discrete() and first_path_info.empty())+	{+	  //fprintf(stdout, "Level %u: FIRST\n", child_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);+	  stats.group_size_approx = 1.0;+	  /*+	   * Reset all_same_level+	   */+	  all_same_level = child_level;+	  /*+	   * Mark the current path to be the first and best one and save it+	   */+	  const unsigned int base_size = search_stack.size();+	  best_path_info.clear();+	  //fprintf(stdout, " New base is: ");+	  for(unsigned int i = 0; i < base_size; i++) {+	    search_stack[i].fp_on = true;+	    search_stack[i].fp_cert_equal = true;+	    search_stack[i].fp_extendable = TreeNode::YES;+	    search_stack[i].in_best_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);+	  /* Copy certificates */+	  certificate_first_path = certificate_current_path;+	  certificate_best_path = certificate_current_path;++	  /* From now on, compare certificates when refining */+	  refine_compare_certificate = true;++	  if(opt_use_failure_recording)+	    failure_recording_hashes.resize(base_size);+	  +	  /*+	  for(unsigned int j = 0; j < search_stack.size(); j++)+	    fprintf(stderr, "%u ", search_stack[j].split_element);+	  fprintf(stderr, "\n");+	  p.print(stderr); fprintf(stderr, "\n");+	  */+	  +	  /*+	   * Backtrack to the previous level+	   */+	  continue;+	}+++      if(p.is_discrete() and child_node.fp_cert_equal)+	{+	  /*+	   * A leaf node that is equal to the first one.+	   * An automorphism found: aut[i] = elements[first_path_labeling[i]]+	   */+	  goto handle_first_path_automorphism;+	}+++      if(!p.is_discrete())+	{+	  Partition::Cell* next_split_cell = 0;+	  /*+	   * An internal, non-leaf node+	   */+	  if(opt_use_comprec)+	    {+	      assert(p.nof_discrete_cells() <=+		     cr_cep_stack[cr_cep_index].discrete_cell_limit);+	      assert(cr_level == child_node.cr_level);+++	      if(p.nof_discrete_cells() ==+		 cr_cep_stack[cr_cep_index].discrete_cell_limit)+		{+		  /* We have reached the end of a component */+		  assert(cr_cep_index != 0);+		  CR_CEP& cep = cr_cep_stack[cr_cep_index];++		  /* First, compare with respect to the first path */+		  if(first_path_info.empty() or child_node.fp_cert_equal) {+		    if(cep.first_checked == false)+		      {+			/* First time, go to the next component */+			cep.first_checked = true;+		      }+		    else+		      {+			assert(!first_path_info.empty());+			assert(cep.creation_level < search_stack.size());+			TreeNode& old_info = search_stack[cep.creation_level];+			/* If the component was found when on the first path,+			 * handle the found automorphism as the other+			 * first path automorphisms */+			if(old_info.fp_on)+			  goto handle_first_path_automorphism;+		      }+		  }++		  if(canonical and+		     !first_path_info.empty() and+		     child_node.cmp_to_best_path >= 0) {+		    if(cep.best_checked == false)+		      {+			/* First time, go to the next component */+			cep.best_checked = true;+		      }+		    else+		      {+			assert(cep.creation_level < search_stack.size());+			TreeNode& old_info = search_stack[cep.creation_level];+			if(child_node.cmp_to_best_path == 0) {+			  /* If the component was found when on the best path,+			   * handle the found automorphism as the other+			   * best path automorphisms */+			  if(old_info.in_best_path)+			    goto handle_best_path_automorphism;+			  /* Otherwise, we do not remember the automorhism as+			   * we didn't memorize the path that was invariant+			   * equal to the best one and passed through the+			   * component.+			   * Thus we can only backtrack to the previous level */+			  child_node.cmp_to_best_path = -1;+			  if(!child_node.fp_cert_equal)+			    {+			      continue;+			    }+			}+			else {+			  assert(child_node.cmp_to_best_path > 0);+			  if(old_info.in_best_path)+			    {+			      stats.nof_canupdates++;+			      /*+			       * Update canonical labeling and its inverse+			       */+			      for(unsigned int i = 0; i < N; i++) {+				if(p.get_cell(p.elements[i])->is_unit()) {+				  best_path_labeling[p.elements[i]] = i;+				  best_path_labeling_inv[i] = p.elements[i];+				}+			      }+			      //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 to be the best one and save prefix */+			      unsigned int postfix_start = cep.creation_level;+			      assert(postfix_start < best_path_info.size());+			      while(p.get_cell(best_path_info[postfix_start].splitting_element)->is_unit()) {+				postfix_start++;+				assert(postfix_start < best_path_info.size());+			      }+			      unsigned int postfix_start_cert = best_path_info[postfix_start].certificate_index;+			      std::vector<PathInfo> best_path_temp = best_path_info;+			      best_path_info.clear();+			      for(unsigned int i = 0; i < search_stack.size(); i++) {+				TreeNode& ss_info = search_stack[i];+				PathInfo  bp_info;+				ss_info.cmp_to_best_path = 0;+				ss_info.in_best_path = true;+				bp_info.splitting_element = ss_info.split_element;+				bp_info.certificate_index = ss_info.certificate_index;+				bp_info.subcertificate_length = ss_info.subcertificate_length;+				bp_info.eqref_hash = ss_info.eqref_hash;+				best_path_info.push_back(bp_info);+			      }+			      /* Copy the postfix of the previous best path */+			      for(unsigned int i = postfix_start;+				  i < best_path_temp.size();+				  i++)+				{+				  best_path_info.push_back(best_path_temp[i]);+				  best_path_info[best_path_info.size()-1].certificate_index =+				    best_path_info[best_path_info.size()-2].certificate_index ++				    best_path_info[best_path_info.size()-2].subcertificate_length;+				}+			      std::vector<unsigned int> certificate_best_path_old = certificate_best_path;+			      certificate_best_path = certificate_current_path;+			      for(unsigned int i = postfix_start_cert;  i < certificate_best_path_old.size(); i++)+				certificate_best_path.push_back(certificate_best_path_old[i]);+			      assert(certificate_best_path.size() == best_path_info.back().certificate_index + best_path_info.back().subcertificate_length);+			      /* Backtrack to the previous level */+			      continue;+			    }+			}+		      }+		  }++		  /* No backtracking performed, go to next componenet */+		  cr_level = cep.next_cr_level;+		  cr_cep_index = cep.next_cep_index;+		}++	      /* Check if the current component has been split into+	       * new non-uniformity subcomponents */+	      //if(nucr_find_first_component(cr_level) == true and+	      // p.nof_discrete_cells() + cr_component_elements <+	      // cr_cep_stack[cr_cep_index].discrete_cell_limit)+	      if(nucr_find_first_component(cr_level, cr_component,+					   cr_component_elements,+					   next_split_cell) == true and+		 p.nof_discrete_cells() + cr_component_elements <+		 cr_cep_stack[cr_cep_index].discrete_cell_limit)+		{+		  const unsigned int next_cr_level =+		    p.cr_split_level(cr_level, cr_component);+		  CR_CEP cep;+		  cep.creation_level = search_stack.size();+		  cep.discrete_cell_limit =+		    p.nof_discrete_cells() + cr_component_elements;+		  cep.next_cr_level = cr_level;+		  cep.next_cep_index = cr_cep_index;+		  cep.first_checked = false;+		  cep.best_checked = false;+		  cr_cep_index = cr_cep_stack.size();+		  cr_cep_stack.push_back(cep);+		  cr_level = next_cr_level;+		}+	    }+++	  /*+	   * Build the next node info+	   */+	  /* Find the next cell to be splitted */+	  if(!next_split_cell)+	    next_split_cell = find_next_cell_to_be_splitted(p.get_cell(p.elements[current_node.split_cell_first]));+	  //Partition::Cell * const next_split_cell = find_next_cell_to_be_splitted(p.get_cell(p.elements[current_node.split_cell_first]));+	  child_node.split_cell_first = next_split_cell->first;+	  child_node.split_element = TreeNode::SPLIT_START;+	  child_node.certificate_index = certificate_index;+	  child_node.partition_bt_point = p.set_backtrack_point();+	  child_node.long_prune_redundant.clear();+	  child_node.long_prune_begin = current_node.long_prune_begin;++	  /* Save component recursion info for backtracking */+	  child_node.cr_level = cr_level;+	  child_node.cr_cep_stack_size = cr_cep_stack.size();+	  child_node.cr_cep_index = cr_cep_index;++	  search_stack.push_back(child_node);+	  continue;+	}++      /*+       * A leaf node not in the first path or equivalent to the first path+       */++++      if(child_node.cmp_to_best_path > 0)+	{+	  /*+	   * A new, better representative found+	   */+	  //fprintf(stdout, "Level %u: NEW BEST\n", child_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(current_level+1 == base_size);+	  best_path_info.clear();+	  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.subcertificate_length = search_stack[i].subcertificate_length;+	    path_info.eqref_hash = search_stack[i].eqref_hash;+	    best_path_info.push_back(path_info);+	  }+	  certificate_best_path = certificate_current_path;+	  /*+	   * Backtrack to the previous level+	   */+	  continue;+	}++      +    handle_best_path_automorphism:+      /*+       *+       * Best path automorphism handling+       *+       */+      {++	/*+	 * Equal to the previous best path+	 */+	if(p.is_discrete())+	  {+#if defined(BLISS_CONSISTENCY_CHECKS)+	    /* 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+	  }+	else+	  {+	    /* An automorphism that was found before the partition was discrete.+	     * Set the image of all elements in non-disrete cells accordingly */+	    for(Partition::Cell* c = p.first_nonsingleton_cell; c;+		c = c->next_nonsingleton) {+	      for(unsigned int i = c->first; i < c->first+c->length; i++)+		if(p.get_cell(p.elements[best_path_labeling[p.elements[i]]])->is_unit())+		  best_path_automorphism[p.elements[best_path_labeling[p.elements[i]]]] = p.elements[i];+		else+		  best_path_automorphism[p.elements[i]] = p.elements[i];+	    }+	  }+	+#if defined(BLISS_VERIFY_AUTOMORPHISMS)+	/* Verify that it really is an automorphism */+	if(!is_automorphism(best_path_automorphism))+	  fatal_error("Best path automorhism validation check failed");+#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++;+	}++	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++;+	}++	if(opt_use_long_prune)+	  {+	    /* Record automorphism */+	    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())+	  {+	    /* Some orbits were merged */+	    /* Report automorphism */+	    if(report_hook)+	      (*report_hook)(report_user_param,+			     get_nof_vertices(),+			     best_path_automorphism);+	    /* Update statistics */+	    stats.nof_generators++;+	  }+	  +	/*+	 * Compute backjumping level+	 */+	unsigned int backjumping_level = current_level+1-1;+	if(!first_path_orbits.is_minimal_representative(search_stack[gca_level_with_first].split_element))+	  {+	    backjumping_level = gca_level_with_first;+	  }+	else+	  {+	    assert(!best_path_orbits.is_minimal_representative(search_stack[gca_level_with_best].split_element));+	    backjumping_level = gca_level_with_best;+	  }+	/* Backtrack */+	search_stack.resize(backjumping_level + 1);+	continue;+      }+++      _INTERNAL_ERROR();++      +    handle_first_path_automorphism:+      /*+       *+       * A first-path automorphism: aut[i] = elements[first_path_labeling[i]]+       *+       */+      ++      if(p.is_discrete())+	{+#if defined(BLISS_CONSISTENCY_CHECKS)+	  /* Verify that the complete automorphism is correctly built */+	  for(unsigned int i = 0; i < N; i++)+	    assert(first_path_automorphism[i] ==+		   p.elements[first_path_labeling[i]]);+#endif+	}+      else+	{+	  /* An automorphism that was found before the partition was discrete.+	   * Set the image of all elements in non-disrete cells accordingly */+	  for(Partition::Cell* c = p.first_nonsingleton_cell; c;+	      c = c->next_nonsingleton) {+	    for(unsigned int i = c->first; i < c->first+c->length; i++)+	      if(p.get_cell(p.elements[first_path_labeling[p.elements[i]]])->is_unit())+		first_path_automorphism[p.elements[first_path_labeling[p.elements[i]]]] = p.elements[i];+	      else+		first_path_automorphism[p.elements[i]] = p.elements[i];+	  }+	}++#if defined(BLISS_VERIFY_AUTOMORPHISMS)+      /* Verify that it really is an automorphism */+      if(!is_automorphism(first_path_automorphism))+	fatal_error("First path automorphism validation check failed");+#endif+      +      if(opt_use_long_prune)+	{+	  long_prune_add_automorphism(first_path_automorphism);+	}+      +      /*+       * Update orbit information+       */+      update_orbit_information(first_path_orbits, first_path_automorphism);+      +      /*+       * Compute backjumping level+       */+      for(unsigned int i = 0; i < search_stack.size(); i++) {+	TreeNode& n = search_stack[i];+	if(n.fp_on) {+	  ;+	} else {+	  n.fp_extendable = TreeNode::YES;+	}+      }++      /* Report automorphism by calling the user defined hook function */+      if(report_hook)+	(*report_hook)(report_user_param,+		       get_nof_vertices(),+		       first_path_automorphism);++      /* Update statistics */+      stats.nof_generators++;+      continue;++    } /* while(!search_stack.empty()) */+++++  /* Free "long prune" technique memory */+  if(opt_use_long_prune)+    long_prune_deallocate();++  /* Release component recursion data in partition */+  if(opt_use_comprec)+    p.cr_free();+}+++++void+AbstractGraph::find_automorphisms(Stats& stats,+				  void (*hook)(void *user_param,+					       unsigned int n,+					       const unsigned int *aut),+				  void *user_param)+{+  report_hook = hook;+  report_user_param = user_param;++  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,+			      void (*hook)(void *user_param,+					   unsigned int n,+					   const unsigned int *aut),+			      void *user_param)+{++  report_hook = hook;+  report_user_param = user_param;++  search(true, stats);++  return best_path_labeling;+}+++++/*-------------------------------------------------------------------------+ *+ * Routines for directed graphs+ *+ *-------------------------------------------------------------------------*/++Digraph::Vertex::Vertex()+{+  color = 0;+}+++Digraph::Vertex::~Vertex()+{+  ;+}+++void+Digraph::Vertex::add_edge_to(const unsigned int other_vertex)+{+  edges_out.push_back(other_vertex);+}+++void+Digraph::Vertex::add_edge_from(const unsigned int other_vertex)+{+  edges_in.push_back(other_vertex);+}+++void+Digraph::Vertex::remove_duplicate_edges(std::vector<bool>& tmp)+{+#if defined(BLISS_CONSISTENCY_CHECKS)+  /* Pre-conditions  */+  for(unsigned int i = 0; i < tmp.size(); i++) assert(tmp[i] == false);+#endif+  for(std::vector<unsigned int>::iterator iter = edges_out.begin();+      iter != edges_out.end(); )+    {+      const unsigned int dest_vertex = *iter;+      if(tmp[dest_vertex] == true)+	{+	  /* A duplicate edge found! */+	  iter = edges_out.erase(iter);+	}+      else+	{+	  /* Not seen earlier, mark as seen */+	  tmp[dest_vertex] = true;+	  iter++;+	}+    }++  /* Clear tmp */+  for(std::vector<unsigned int>::iterator iter = edges_out.begin();+      iter != edges_out.end();+      iter++)+    {+      tmp[*iter] = false;+    }++  for(std::vector<unsigned int>::iterator iter = edges_in.begin();+      iter != edges_in.end(); )+    {+      const unsigned int dest_vertex = *iter;+      if(tmp[dest_vertex] == true)+	{+	  /* A duplicate edge found! */+	  iter = edges_in.erase(iter);+	}+      else+	{+	  /* Not seen earlier, mark as seen */+	  tmp[dest_vertex] = true;+	  iter++;+	}+    }++  /* Clear tmp */+  for(std::vector<unsigned int>::iterator iter = edges_in.begin();+      iter != edges_in.end();+      iter++)+    {+      tmp[*iter] = false;+    }+#if defined(BLISS_CONSISTENCY_CHECKS)+  /* Post-conditions  */+  for(unsigned int i = 0; i < tmp.size(); i++) assert(tmp[i] == false);+#endif+}+++/**+ * Sort the edges entering and leaving the vertex according to+ * the vertex number of the other edge end.+ * Time complexity: O(e log(e)), where e is the number of edges+ * entering/leaving the vertex.+ */+void+Digraph::Vertex::sort_edges()+{+  std::sort(edges_in.begin(), edges_in.end());+  std::sort(edges_out.begin(), edges_out.end());+}++++++/*-------------------------------------------------------------------------+ *+ * Constructor and destructor for directed graphs+ *+ *-------------------------------------------------------------------------*/+++Digraph::Digraph(const unsigned int nof_vertices)+{+  vertices.resize(nof_vertices);+  sh = shs_flm;+}+++Digraph::~Digraph()+{+  ;+}+++unsigned int+Digraph::add_vertex(const unsigned int color)+{+  const unsigned int new_vertex_num = vertices.size();+  vertices.resize(new_vertex_num + 1);+  vertices.back().color = color;+  return new_vertex_num;+}+++void+Digraph::add_edge(const unsigned int vertex1, const unsigned int vertex2)+{+  assert(vertex1 < get_nof_vertices());+  assert(vertex2 < get_nof_vertices());+  vertices[vertex1].add_edge_to(vertex2);+  vertices[vertex2].add_edge_from(vertex1);+}+++void+Digraph::change_color(const unsigned int vertex, const unsigned int new_color)+{+  assert(vertex < get_nof_vertices());+  vertices[vertex].color = new_color;+}+++void+Digraph::sort_edges()+{+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    vertices[i].sort_edges();+}+++int+Digraph::cmp(Digraph& other)+{+  /* Compare the numbers of vertices */+  if(get_nof_vertices() < other.get_nof_vertices())+    return -1;+  if(get_nof_vertices() > other.get_nof_vertices())+    return 1;+  /* Compare vertex colors */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      if(vertices[i].color < other.vertices[i].color)+	return -1;+      if(vertices[i].color > other.vertices[i].color)+	return 1;+    }+  /* Compare vertex degrees */+  remove_duplicate_edges();+  other.remove_duplicate_edges();+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      if(vertices[i].nof_edges_in() < other.vertices[i].nof_edges_in())+	return -1;+      if(vertices[i].nof_edges_in() > other.vertices[i].nof_edges_in())+	return 1;+      if(vertices[i].nof_edges_out() < other.vertices[i].nof_edges_out())+	return -1;+      if(vertices[i].nof_edges_out() > other.vertices[i].nof_edges_out())+	return 1;+    }+  /* Compare edges */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      Vertex& v1 = vertices[i];+      Vertex& v2 = other.vertices[i];+      v1.sort_edges();+      v2.sort_edges();+      std::vector<unsigned int>::const_iterator ei1 = v1.edges_in.begin();+      std::vector<unsigned int>::const_iterator ei2 = v2.edges_in.begin();+      while(ei1 != v1.edges_in.end())+	{+	  if(*ei1 < *ei2)+	    return -1;+	  if(*ei1 > *ei2)+	    return 1;+	  ei1++;+	  ei2++;+	}+      ei1 = v1.edges_out.begin();+      ei2 = v2.edges_out.begin();+      while(ei1 != v1.edges_out.end())+	{+	  if(*ei1 < *ei2)+	    return -1;+	  if(*ei1 > *ei2)+	    return 1;+	  ei1++;+	  ei2++;+	}+    }+  return 0;+}+++++Digraph*+Digraph::permute(const std::vector<unsigned int>& perm) const+{+  Digraph* const g = new Digraph(get_nof_vertices());+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      const Vertex& v = vertices[i];+      g->change_color(perm[i], v.color);+      for(std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+	  ei != v.edges_out.end();+	  ei++)+	{+	  g->add_edge(perm[i], perm[*ei]);+	}+    }+  g->sort_edges();+  return g;+}+++Digraph*+Digraph::permute(const unsigned int* const perm) const+{+  Digraph* const g = new Digraph(get_nof_vertices());+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      const Vertex &v = vertices[i];+      g->change_color(perm[i], v.color);+      for(std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+	  ei != v.edges_out.end();+	  ei++)+	{+	  g->add_edge(perm[i], perm[*ei]);+	}+    }+  g->sort_edges();+  return g;+}++++++/*-------------------------------------------------------------------------+ *+ * Print graph in graphviz format+ *+ *-------------------------------------------------------------------------*/+++void+Digraph::write_dot(const char* const filename)+{+  FILE* const fp = fopen(filename, "w");+  if(fp)+    {+      write_dot(fp);+      fclose(fp);+    }+}+++void+Digraph::write_dot(FILE* const fp)+{+  remove_duplicate_edges();++  fprintf(fp, "digraph g {\n");++  unsigned int vnum = 0;+  for(std::vector<Vertex>::const_iterator vi = vertices.begin();+      vi != vertices.end();+      vi++, vnum++)+    {+      const Vertex& v = *vi;+      fprintf(fp, "v%u [label=\"%u:%u\"];\n", vnum, vnum, v.color);+      for(std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+	  ei != v.edges_out.end();+	  ei++)+	{+	  fprintf(fp, "v%u -> v%u\n", vnum, *ei);+	}+    }++  fprintf(fp, "}\n");+}+++void+Digraph::remove_duplicate_edges()+{+  std::vector<bool> tmp(get_nof_vertices(), false);++  for(std::vector<Vertex>::iterator vi = vertices.begin();+      vi != vertices.end();+      vi++)+    {+#if defined(BLISS_EXPENSIVE_CONSISTENCY_CHECKS)+      for(unsigned int i = 0; i < tmp.size(); i++) assert(tmp[i] == false);+#endif+      (*vi).remove_duplicate_edges(tmp);+    }+}++++++/*-------------------------------------------------------------------------+ *+ * Get a hash value for the graph.+ *+ *-------------------------------------------------------------------------*/++unsigned int+Digraph::get_hash()+{+  remove_duplicate_edges();+  sort_edges();++  UintSeqHash h;++  h.update(get_nof_vertices());++  /* Hash the color of each vertex */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      h.update(vertices[i].color);+    }++  /* Hash the edges */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      Vertex &v = vertices[i];+      for(std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+	  ei != v.edges_out.end();+	  ei++)+	{+	  h.update(i);+	  h.update(*ei);+	}+    }++  return h.get_value();+}++++/*-------------------------------------------------------------------------+ *+ * Read directed graph in the DIMACS format.+ * Returns 0 if an error occurred.+ *+ *-------------------------------------------------------------------------*/++Digraph*+Digraph::read_dimacs(FILE* const fp, FILE* const errstr)+{+  Digraph* g = 0;+  unsigned int nof_vertices;+  unsigned int nof_edges;+  unsigned int line_num = 1;++  const bool verbose = false;+  FILE* const verbstr = stdout;+  +  /* Read comments and the problem definition line */+  while(1)+    {+      int c = getc(fp);+      if(c == 'c')+	{+	  /* A comment, ignore the rest of the line */+	  while((c = getc(fp)) != '\n')+	    {+	      if(c == EOF) {+		if(errstr)+		  fprintf(errstr, "error in line %u: not in DIMACS format\n",+			  line_num);+		goto error_exit;+	      }+	    }+	  line_num++;+	  continue;+	}+      if(c == 'p')+	{+	  /* The problem definition line */+	  if(fscanf(fp, " edge %u %u\n", &nof_vertices, &nof_edges) != 2)+	    {+	      if(errstr)+		fprintf(errstr, "error in line %u: not in DIMACS format\n",+			line_num);+	      goto error_exit;+	    }+	  line_num++;+	  break;+	}+      if(errstr)+	fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num);+      goto error_exit;+    }+  +  if(nof_vertices <= 0)+    {+      if(errstr)+	fprintf(errstr, "error: no vertices\n");+      goto error_exit;+    }+  if(verbose)+    {+      fprintf(verbstr, "Instance has %d vertices and %d edges\n",+	      nof_vertices, nof_edges);+      fflush(verbstr);+    }++  g = new Digraph(nof_vertices);++  //+  // Read vertex colors+  //+  if(verbose)+    {+      fprintf(verbstr, "Reading vertex colors...\n");+      fflush(verbstr);+    }+  while(1)+    {+      int c = getc(fp);+      if(c != 'n')+	{+	  ungetc(c, fp);+	  break;+	}+      ungetc(c, fp);+      unsigned int vertex;+      unsigned int color;+      if(fscanf(fp, "n %u %u\n", &vertex, &color) != 2)+	{+	  if(errstr)+	    fprintf(errstr, "error in line %u: not in DIMACS format\n",+		    line_num);+	  goto error_exit;+	}+      if(!((vertex >= 1) && (vertex <= nof_vertices)))+	{+	  if(errstr)+	    fprintf(errstr,+		    "error in line %u: vertex %u not in range [1,...%u]\n",+		    line_num, vertex, nof_vertices);+	  goto error_exit;+	}+      line_num++;+      g->change_color(vertex - 1, color);+    }+  if(verbose)+    {+      fprintf(verbstr, "Done\n");+      fflush(verbstr);+    }++  //+  // Read edges+  //+  if(verbose)+    {+      fprintf(verbstr, "Reading edges...\n");+      fflush(verbstr);+    }+  for(unsigned i = 0; i < nof_edges; i++)+    {+      unsigned int from, to;+      if(fscanf(fp, "e %u %u\n", &from, &to) != 2)+	{+	  if(errstr)+	    fprintf(errstr, "error in line %u: not in DIMACS format\n",+		    line_num);+	  goto error_exit;+	}+      if(not((1 <= from) and (from <= nof_vertices)))+	{+	  if(errstr)+	    fprintf(errstr,+		    "error in line %u: vertex %u not in range [1,...%u]\n",+		    line_num, from, nof_vertices);+	  goto error_exit;+	}+      if(not((1 <= to) and (to <= nof_vertices)))+	{+	  if(errstr)+	    fprintf(errstr,+		    "error in line %u: vertex %u not in range [1,...%u]\n",+		    line_num, to, nof_vertices);+	  goto error_exit;+	}+      line_num++;+      g->add_edge(from-1, to-1);+    }+  if(verbose)+    {+      fprintf(verbstr, "Done\n");+      fflush(verbstr);+    }+  +  return g;++ error_exit:+  if(g)+    delete g;+  return 0;+}++++++void+Digraph::write_dimacs(FILE* const fp)+{+  remove_duplicate_edges();+  sort_edges();++  /* First count the total number of edges */+  unsigned int nof_edges = 0;+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      nof_edges += vertices[i].edges_out.size();+    }++  /* Output the "header" line */+  fprintf(fp, "p edge %u %u\n", get_nof_vertices(), nof_edges);++  /* Print the color of each vertex */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      Vertex& v = vertices[i];+      fprintf(fp, "n %u %u\n", i+1, v.color);+      /*+      if(v.color != 0)+	{+	  fprintf(fp, "n %u %u\n", i+1, v.color);+	}+      */+    }++  /* Print the edges */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      Vertex& v = vertices[i];+      for(std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+	  ei != v.edges_out.end();+	  ei++)+	{+	  fprintf(fp, "e %u %u\n", i+1, (*ei)+1);+	}+    }+}+++++++++/*-------------------------------------------------------------------------+ *+ * Partition independent invariants+ *+ *-------------------------------------------------------------------------*/++unsigned int+Digraph::vertex_color_invariant(const Digraph* const g, const unsigned int vnum)+{+  return g->vertices[vnum].color;+}++unsigned int+Digraph::indegree_invariant(const Digraph* const g, const unsigned int vnum)+{+  return g->vertices[vnum].nof_edges_in();+}++unsigned int+Digraph::outdegree_invariant(const Digraph* const g, const unsigned int vnum)+{+  return g->vertices[vnum].nof_edges_out();+}++unsigned int+Digraph::selfloop_invariant(const Digraph* const g, const unsigned int vnum)+{+  /* Quite inefficient but luckily not in the critical path */+  const Vertex& v = g->vertices[vnum];+  for(std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+      ei != v.edges_out.end();+      ei++)+    {+      if(*ei == vnum)+	return 1;+    }+  return 0;+}++++++/*-------------------------------------------------------------------------+ *+ * Refine the partition p according to a partition independent invariant+ *+ *-------------------------------------------------------------------------*/++bool+Digraph::refine_according_to_invariant(unsigned int (*inv)(const Digraph* const g,+							   const unsigned int v))+{+  bool refined = false;++  for(Partition::Cell* cell = p.first_nonsingleton_cell; cell; )+    {+      +      Partition::Cell* const next_cell = cell->next_nonsingleton;+      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++;+	  }+	}+      Partition::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+ *+ *-------------------------------------------------------------------------*/++bool+Digraph::split_neighbourhood_of_cell(Partition::Cell* const cell)+{+  ++  const bool was_equal_to_first = refine_equal_to_first;++  if(compute_eqref_hash)+    {+      eqref_hash.update(cell->first);+      eqref_hash.update(cell->length);+    }++  const unsigned int* ep = p.elements + cell->first;+  for(unsigned int i = cell->length; i > 0; i--)+    {+      const Vertex& v = vertices[*ep++];+      +      std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+      for(unsigned int j = v.nof_edges_out(); j != 0; j--)+	{+	  const unsigned int dest_vertex = *ei++;+	  Partition::Cell* const neighbour_cell = p.get_cell(dest_vertex);+	  if(neighbour_cell->is_unit())+	    continue;+	  const unsigned int ival = ++p.invariant_values[dest_vertex];+	  if(ival > neighbour_cell->max_ival) {+	    neighbour_cell->max_ival = ival;+	    neighbour_cell->max_ival_count = 1;+	    if(ival == 1)+	      neighbour_heap.insert(neighbour_cell->first);+	  }+	  else if(ival == neighbour_cell->max_ival) {+	    neighbour_cell->max_ival_count++;+	  }+	}+    }++  while(!neighbour_heap.is_empty())+    {+      const unsigned int start = neighbour_heap.remove();+      Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]);+      +      if(compute_eqref_hash)+	{+	  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);+	}+++      Partition::Cell* const last_new_cell = p.zplit_cell(neighbour_cell, true);++      /* Update certificate and hash if needed */+      const Partition::Cell* c = neighbour_cell;+      while(1)+	{+	  if(in_search)+	    {+	      /* Build certificate */+	      cert_add_redundant(CERT_SPLIT, c->first, c->length);+	      /* No need to continue? */+	      if(refine_compare_certificate and+		 (refine_equal_to_first == false) and+		 (refine_cmp_to_best < 0))+		goto worse_exit;+	    }+	  if(compute_eqref_hash)+	    {+	      eqref_hash.update(c->first);+	      eqref_hash.update(c->length);+	    }+	  if(c == last_new_cell)+	    break;+	  c = c->next;+	}+    }++  if(cell->is_in_splitting_queue())+    {+      return false;+    }+++  ep = p.elements + cell->first;+  for(unsigned int i = cell->length; i > 0; i--)+    {+      const Vertex& v = vertices[*ep++];++      std::vector<unsigned int>::const_iterator ei = v.edges_in.begin();+      for(unsigned int j = v.nof_edges_in(); j > 0; j--)+	{+	  const unsigned int dest_vertex = *ei++;+	  Partition::Cell* const neighbour_cell = p.get_cell(dest_vertex);+	  if(neighbour_cell->is_unit())+	    continue;+	  const unsigned int ival = ++p.invariant_values[dest_vertex];+	  if(ival > neighbour_cell->max_ival)+	    {+	      neighbour_cell->max_ival = ival;+	      neighbour_cell->max_ival_count = 1;+	      if(ival == 1)+		neighbour_heap.insert(neighbour_cell->first);+	    }+	  else if(ival == neighbour_cell->max_ival) {+	    neighbour_cell->max_ival_count++;+	  }+	}+    }++  while(!neighbour_heap.is_empty())+    {+      const unsigned int start = neighbour_heap.remove();+      Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]);++      if(compute_eqref_hash)+	{+	  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);+	}++      Partition::Cell* const last_new_cell = p.zplit_cell(neighbour_cell, true);++      /* Update certificate and hash if needed */+      const Partition::Cell* c = neighbour_cell;+      while(1)+	{+	  if(in_search)+	    {+	      /* Build certificate */+	      cert_add_redundant(CERT_SPLIT, c->first, c->length);+	      /* No need to continue? */+	      if(refine_compare_certificate and+		 (refine_equal_to_first == false) and+		 (refine_cmp_to_best < 0))+		goto worse_exit;+	    }+	  if(compute_eqref_hash)+	    {+	      eqref_hash.update(c->first);+	      eqref_hash.update(c->length);+	    }+	  if(c == last_new_cell)+	    break;+	  c = c->next;+	}+    }+++  if(refine_compare_certificate and+     (refine_equal_to_first == false) and+     (refine_cmp_to_best < 0))+    return true;++  return false;+  + worse_exit:+  /* Clear neighbour heap */+  UintSeqHash rest;+  while(!neighbour_heap.is_empty())+    {+      const unsigned int start = neighbour_heap.remove();+      Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]);+      if(opt_use_failure_recording and was_equal_to_first)+	{+	  rest.update(neighbour_cell->first);+	  rest.update(neighbour_cell->length);+	  rest.update(neighbour_cell->max_ival);+	  rest.update(neighbour_cell->max_ival_count);+	}+      neighbour_cell->max_ival = 0;+      neighbour_cell->max_ival_count = 0;+      p.clear_ivs(neighbour_cell);+    }+  if(opt_use_failure_recording and was_equal_to_first)+    {+      for(unsigned int i = p.splitting_queue.size(); i > 0; i--)+	{+	  Partition::Cell* const cell = p.splitting_queue.pop_front();+	  rest.update(cell->first);+	  rest.update(cell->length);+	  p.splitting_queue.push_back(cell);+	}+      rest.update(failure_recording_fp_deviation);+      failure_recording_fp_deviation = rest.get_value();+    }++   return true;+}+++bool+Digraph::split_neighbourhood_of_unit_cell(Partition::Cell* const unit_cell)+{+++  const bool was_equal_to_first = refine_equal_to_first;++  if(compute_eqref_hash)+    {+      eqref_hash.update(0x87654321);+      eqref_hash.update(unit_cell->first);+      eqref_hash.update(1);+    }++  const Vertex& v = vertices[p.elements[unit_cell->first]];++  /*+   * Phase 1+   * Refine neighbours according to the edges that leave the vertex v+   */+  std::vector<unsigned int>::const_iterator ei = v.edges_out.begin();+  for(unsigned int j = v.nof_edges_out(); j > 0; j--)+    {+      const unsigned int dest_vertex = *ei++;+      Partition::Cell* const neighbour_cell = p.get_cell(dest_vertex);+   +      if(neighbour_cell->is_unit()) {+	if(in_search) {+	  /* Remember neighbour in order to generate certificate */+	  neighbour_heap.insert(neighbour_cell->first);+	}+	continue;+      }+      if(neighbour_cell->max_ival_count == 0)+	{+	  neighbour_heap.insert(neighbour_cell->first);+	}+      neighbour_cell->max_ival_count++;+      +      unsigned int* const swap_position =+	p.elements + neighbour_cell->first + neighbour_cell->length -+	neighbour_cell->max_ival_count;+      *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();+      Partition::Cell* neighbour_cell =	p.get_cell(p.elements[start]);++#if defined(BLISS_CONSISTENCY_CHECKS)+      assert(neighbour_cell->first == start);+      if(neighbour_cell->is_unit()) {+	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++      if(compute_eqref_hash)+	{+	  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 and+	 neighbour_cell->max_ival_count != neighbour_cell->length)+	{+	  +	  Partition::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)+	    {+	      p.element_to_cell_map[*ep] = new_cell;+	      ep++;+	    }+	  neighbour_cell->max_ival_count = 0;++	  +	  if(compute_eqref_hash)+	    {+	      /* 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 */+	  if(neighbour_cell->is_in_splitting_queue()) {+	    /* Both cells must be included in splitting_queue in order+	       to have refinement to equitable partition */+	    p.splitting_queue_add(new_cell);+	  } else {+	    Partition::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.splitting_queue_add(min_cell);+	  if(max_cell->is_unit()) {+	    /* Put the "larger" cell also in splitting_queue */+	    p.splitting_queue_add(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;+	      j > 0;+	      j--, i++)+	    {+	      /* Build certificate */+	      cert_add(CERT_EDGE, unit_cell->first, i);+	      /* No need to continue? */+	      if(refine_compare_certificate and+		 (refine_equal_to_first == false) and+		 (refine_cmp_to_best < 0))+		goto worse_exit;+	    }+	} /* if(in_search) */+    } /* while(!neighbour_heap.is_empty()) */++  /*+   * Phase 2+   * Refine neighbours according to the edges that enter the vertex v+   */+  ei = v.edges_in.begin();+  for(unsigned int j = v.nof_edges_in(); j > 0; j--)+    {+      const unsigned int dest_vertex = *ei++;+      Partition::Cell* const neighbour_cell = p.get_cell(dest_vertex);+      +      if(neighbour_cell->is_unit()) {+	if(in_search) {+	  neighbour_heap.insert(neighbour_cell->first);+	}+	continue;+      }+      if(neighbour_cell->max_ival_count == 0)+	{+	  neighbour_heap.insert(neighbour_cell->first);+	}+      neighbour_cell->max_ival_count++;++      unsigned int* const swap_position =+	p.elements + neighbour_cell->first + neighbour_cell->length -+	neighbour_cell->max_ival_count;+      *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();+      Partition::Cell* neighbour_cell =	p.get_cell(p.elements[start]);++#if defined(BLISS_CONSISTENCY_CHECKS)+      assert(neighbour_cell->first == start);+      if(neighbour_cell->is_unit()) {+	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++      if(compute_eqref_hash)+	{+	  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 and+	 neighbour_cell->max_ival_count != neighbour_cell->length)+	{+	  Partition::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) {+	    p.element_to_cell_map[*ep] = new_cell;+	    ep++;+	  }+	  neighbour_cell->max_ival_count = 0;+	  +	  +	  if(compute_eqref_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 */+	  if(neighbour_cell->is_in_splitting_queue()) {+	    /* Both cells must be included in splitting_queue in order+	       to have refinement to equitable partition */+	    p.splitting_queue_add(new_cell);+	  } else {+	    Partition::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.splitting_queue_add(min_cell);+	    if(max_cell->is_unit()) {+	      /* Put the "larger" cell also in splitting_queue */+	      p.splitting_queue_add(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;+	      j > 0;+	      j--, i++)+	    {+	      /* Build certificate */+	      cert_add(CERT_EDGE, i, unit_cell->first);+	      /* No need to continue? */+	      if(refine_compare_certificate and+		 (refine_equal_to_first == false) and+		 (refine_cmp_to_best < 0))+		goto worse_exit;+	    }+	} /* if(in_search) */+    } /* while(!neighbour_heap.is_empty()) */++  if(refine_compare_certificate and+     (refine_equal_to_first == false) and+     (refine_cmp_to_best < 0))+    return true;++  return false;++ worse_exit:+  /* Clear neighbour heap */+  UintSeqHash rest;+  while(!neighbour_heap.is_empty())+    {+      const unsigned int start = neighbour_heap.remove();+      Partition::Cell* const neighbour_cell = p.get_cell(p.elements[start]);+      if(opt_use_failure_recording and was_equal_to_first)+	{+	  rest.update(neighbour_cell->first);+	  rest.update(neighbour_cell->length);+	  rest.update(neighbour_cell->max_ival_count);+	}+      neighbour_cell->max_ival_count = 0;+    }+  if(opt_use_failure_recording and was_equal_to_first)+    {+      rest.update(failure_recording_fp_deviation);+      failure_recording_fp_deviation = rest.get_value();+    }+  return true;+}++++++/*-------------------------------------------------------------------------+ *+ * Check whether the current partition p is equitable.+ * Performance: very slow, use only for debugging purposes.+ *+ *-------------------------------------------------------------------------*/++bool+Digraph::is_equitable() const+{+  const unsigned int N = get_nof_vertices();+  if(N == 0)+    return true;++  std::vector<unsigned int> first_count = std::vector<unsigned int>(N, 0);+  std::vector<unsigned int> other_count = std::vector<unsigned int>(N, 0);++  /*+   * Check equitabledness w.r.t. outgoing edges+   */+  for(Partition::Cell* cell = p.first_cell; cell; cell = cell->next)+    {+      if(cell->is_unit())+	continue;++      unsigned int* ep = p.elements + cell->first;+      const Vertex& first_vertex = vertices[*ep++];++      /* Count outgoing edges of the first vertex for cells */+      for(std::vector<unsigned int>::const_iterator ei =+	    first_vertex.edges_out.begin();+	  ei != first_vertex.edges_out.end();+	  ei++)+	{+	  first_count[p.get_cell(*ei)->first]++;+	}++      /* Count and compare outgoing edges of the other vertices */+      for(unsigned int i = cell->length; i > 1; i--)+	{+	  const Vertex &vertex = vertices[*ep++];+	  for(std::vector<unsigned int>::const_iterator ei =+		vertex.edges_out.begin();+	      ei != vertex.edges_out.end();+	      ei++)+	    {+	      other_count[p.get_cell(*ei)->first]++;+	    }+	  for(Partition::Cell *cell2 = p.first_cell;+	      cell2;+	      cell2 = cell2->next)+	    {+	      if(first_count[cell2->first] != other_count[cell2->first])+		{+		  /* Not equitable */+		  return false;+		}+	      other_count[cell2->first] = 0;+	    }+	}+      /* Reset first_count */+      for(unsigned int i = 0; i < N; i++)+	first_count[i] = 0;+    }+++  /*+   * Check equitabledness w.r.t. incoming edges+   */+  for(Partition::Cell* cell = p.first_cell; cell; cell = cell->next)+    {+      if(cell->is_unit())+	continue;++      unsigned int* ep = p.elements + cell->first;+      const Vertex& first_vertex = vertices[*ep++];++      /* Count incoming edges of the first vertex for cells */+      for(std::vector<unsigned int>::const_iterator ei =+	    first_vertex.edges_in.begin();+	  ei != first_vertex.edges_in.end();+	  ei++)+	{+	  first_count[p.get_cell(*ei)->first]++;+	}++      /* Count and compare incoming edges of the other vertices */+      for(unsigned int i = cell->length; i > 1; i--)+	{+	  const Vertex &vertex = vertices[*ep++];+	  for(std::vector<unsigned int>::const_iterator ei =+		vertex.edges_in.begin();+	      ei != vertex.edges_in.end();+	      ei++)+	    {+	      other_count[p.get_cell(*ei)->first]++;+	    }+	  for(Partition::Cell *cell2 = p.first_cell;+	      cell2;+	      cell2 = cell2->next)+	    {+	      if(first_count[cell2->first] != other_count[cell2->first])+		{+		  /* Not equitable */+		  return false;+		}+	      other_count[cell2->first] = 0;+	    }+	}+      /* Reset first_count */+      for(unsigned int i = 0; i < N; i++)+	first_count[i] = 0;+    }+  return true;+}++++++/*-------------------------------------------------------------------------+ *+ * Build the initial equitable partition+ *+ *-------------------------------------------------------------------------*/++void+Digraph::make_initial_equitable_partition()+{+  refine_according_to_invariant(&vertex_color_invariant);+  p.splitting_queue_clear();+  //p.print_signature(stderr); fprintf(stderr, "\n");++  refine_according_to_invariant(&selfloop_invariant);+  p.splitting_queue_clear();+  //p.print_signature(stderr); fprintf(stderr, "\n");++  refine_according_to_invariant(&outdegree_invariant);+  p.splitting_queue_clear();+  //p.print_signature(stderr); fprintf(stderr, "\n");++  refine_according_to_invariant(&indegree_invariant);+  p.splitting_queue_clear();+  //p.print_signature(stderr); fprintf(stderr, "\n");++  refine_to_equitable();+  //p.print_signature(stderr); fprintf(stderr, "\n");+}++++++/*-------------------------------------------------------------------------+ *+ * Find the next cell to be splitted+ *+ *-------------------------------------------------------------------------*/++Partition::Cell*+Digraph::find_next_cell_to_be_splitted(Partition::Cell* cell)+{+  switch(sh) {+  case shs_f:   return sh_first();+  case shs_fs:  return sh_first_smallest();+  case shs_fl:  return sh_first_largest();+  case shs_fm:  return sh_first_max_neighbours();+  case shs_fsm: return sh_first_smallest_max_neighbours();+  case shs_flm: return sh_first_largest_max_neighbours();+  default:+    fatal_error("Internal error - unknown splitting heuristics");+    return 0;+  }+}++/** \internal+ * A splitting heuristic.+ * Returns the first nonsingleton cell in the current partition.+ * The argument \a cell is ignored.+ */+Partition::Cell*+Digraph::sh_first()+{+  Partition::Cell* best_cell = 0;+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      best_cell = cell;+      break;+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first smallest nonsingleton cell in the current partition.+ * The argument \a cell is ignored.+ */+Partition::Cell*+Digraph::sh_first_smallest()+{+  Partition::Cell* best_cell = 0;+  unsigned int best_size = UINT_MAX;+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      if(cell->length < best_size)+	{+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first largest nonsingleton cell in the current partition.+ * The argument \a cell is ignored.+ */+Partition::Cell*+Digraph::sh_first_largest()+{+  Partition::Cell* best_cell = 0;+  unsigned int best_size = 0;+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      if(cell->length > best_size)+	{+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first nonsingleton cell with max number of neighbouring+ * nonsingleton cells.+ * Assumes that the partition p is equitable.+ * Assumes that the max_ival fields of the cells are all 0.+ */+Partition::Cell*+Digraph::sh_first_max_neighbours()+{+  Partition::Cell* best_cell = 0;+  int best_value = -1;+  KStack<Partition::Cell*> neighbour_cells_visited;+  neighbour_cells_visited.init(get_nof_vertices());+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      int value = 0;+      const Vertex &v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei;+      ei = v.edges_in.begin();+      for(unsigned int j = v.nof_edges_in(); j > 0; j--)+	{+	  Partition::Cell * const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}++      ei = v.edges_out.begin();+      for(unsigned int j = v.nof_edges_out(); j > 0; j--)+	{+	  Partition::Cell * const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}+      +      if(value > best_value)+	{+	  best_value = value;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first smallest nonsingleton cell with max number of neighbouring+ * nonsingleton cells.+ * Assumes that the partition p is equitable.+ * Assumes that the max_ival fields of the cells are all 0.+ */+Partition::Cell*+Digraph::sh_first_smallest_max_neighbours()+{+  Partition::Cell* best_cell = 0;+  int best_value = -1;+  unsigned int best_size = UINT_MAX;+  KStack<Partition::Cell*> neighbour_cells_visited;+  neighbour_cells_visited.init(get_nof_vertices());+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+	+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+	+      int value = 0;+      const Vertex& v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei;++      ei = v.edges_in.begin();+      for(unsigned int j = v.nof_edges_in(); j > 0; j--)+	{+	  Partition::Cell * const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell * const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}++      ei = v.edges_out.begin();+      for(unsigned int j = v.nof_edges_out(); j > 0; j--)+	{+	  Partition::Cell * const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell * const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}++      if((value > best_value) or+	 (value == best_value and cell->length < best_size))+	{+	  best_value = value;+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first largest nonsingleton cell with max number of neighbouring+ * nonsingleton cells.+ * Assumes that the partition p is equitable.+ * Assumes that the max_ival fields of the cells are all 0.+ */+Partition::Cell*+Digraph::sh_first_largest_max_neighbours()+{+  Partition::Cell* best_cell = 0;+  int best_value = -1;+  unsigned int best_size = 0;+  KStack<Partition::Cell*> neighbour_cells_visited;+  neighbour_cells_visited.init(get_nof_vertices());+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {++      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;++      int value = 0;+      const Vertex &v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei;++      ei = v.edges_in.begin();+      for(unsigned int j = v.nof_edges_in(); j > 0; j--)+	{+	  Partition::Cell* const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}++      ei = v.edges_out.begin();+      for(unsigned int j = v.nof_edges_out(); j > 0; j--)+	{+	  Partition::Cell* const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}++      if((value > best_value) ||+	 (value == best_value && cell->length > best_size))+	{+	  best_value = value;+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}+++++++/*------------------------------------------------------------------------+ *+ * Initialize the certificate size and memory+ *+ *-------------------------------------------------------------------------*/++void+Digraph::initialize_certificate()+{+  certificate_index = 0;+  certificate_current_path.clear();+  certificate_first_path.clear();+  certificate_best_path.clear();+}++++/*+ * Check whether perm is an automorphism.+ * Slow, mainly for debugging and validation purposes.+ */+bool+Digraph::is_automorphism(unsigned int* const perm)+{+  std::set<unsigned int, std::less<unsigned int> > edges1;+  std::set<unsigned int, std::less<unsigned int> > edges2;++#if defined(BLISS_CONSISTENCY_CHECKS)+  if(!is_permutation(get_nof_vertices(), perm))+    _INTERNAL_ERROR();+#endif++  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      Vertex& v1 = vertices[i];+      Vertex& v2 = vertices[perm[i]];++      edges1.clear();+      for(std::vector<unsigned int>::iterator ei = v1.edges_in.begin();+	  ei != v1.edges_in.end();+	  ei++)+	edges1.insert(perm[*ei]);+      edges2.clear();+      for(std::vector<unsigned int>::iterator ei = v2.edges_in.begin();+	  ei != v2.edges_in.end();+	  ei++)+	edges2.insert(*ei);+      if(!(edges1 == edges2))+	return false;++      edges1.clear();+      for(std::vector<unsigned int>::iterator ei = v1.edges_out.begin();+	  ei != v1.edges_out.end();+	  ei++)+	edges1.insert(perm[*ei]);+      edges2.clear();+      for(std::vector<unsigned int>::iterator ei = v2.edges_out.begin();+	  ei != v2.edges_out.end();+	  ei++)+	edges2.insert(*ei);+      if(!(edges1 == edges2))+	return false;+    }++  return true;+}++bool+Digraph::is_automorphism(const std::vector<unsigned int>& perm) const+{++  if(!(perm.size() == get_nof_vertices() and is_permutation(perm)))+    return false;++  std::set<unsigned int, std::less<unsigned int> > edges1;+  std::set<unsigned int, std::less<unsigned int> > edges2;++  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      const Vertex& v1 = vertices[i];+      const Vertex& v2 = vertices[perm[i]];++      edges1.clear();+      for(std::vector<unsigned int>::const_iterator ei = v1.edges_in.begin();+	  ei != v1.edges_in.end();+	  ei++)+	edges1.insert(perm[*ei]);+      edges2.clear();+      for(std::vector<unsigned int>::const_iterator ei = v2.edges_in.begin();+	  ei != v2.edges_in.end();+	  ei++)+	edges2.insert(*ei);+      if(!(edges1 == edges2))+	return false;++      edges1.clear();+      for(std::vector<unsigned int>::const_iterator ei = v1.edges_out.begin();+	  ei != v1.edges_out.end();+	  ei++)+	edges1.insert(perm[*ei]);+      edges2.clear();+      for(std::vector<unsigned int>::const_iterator ei = v2.edges_out.begin();+	  ei != v2.edges_out.end();+	  ei++)+	edges2.insert(*ei);+      if(!(edges1 == edges2))+	return false;+    }++  return true;+}+++++bool+Digraph::nucr_find_first_component(const unsigned int level)+{++  cr_component.clear();+  cr_component_elements = 0;++  /* Find first non-discrete cell in the component level */+  Partition::Cell* first_cell = p.first_nonsingleton_cell;+  while(first_cell)+    {+      if(p.cr_get_level(first_cell->first) == level)+	break;+      first_cell = first_cell->next_nonsingleton;+    }++  /* The component is discrete, return false */+  if(!first_cell)+    return false;+	+  std::vector<Partition::Cell*> component;+  first_cell->max_ival = 1;+  component.push_back(first_cell);++  for(unsigned int i = 0; i < component.size(); i++)+    {+      Partition::Cell* const cell = component[i];+	  +      const Vertex& v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei;++      ei = v.edges_out.begin();+      for(unsigned int j = v.nof_edges_out(); j > 0; j--)+	{+	  const unsigned int neighbour = *ei++;+	  Partition::Cell* const neighbour_cell = p.get_cell(neighbour);++	  /* Skip unit neighbours */+	  if(neighbour_cell->is_unit())+	    continue;+	  /* Already marked to be in the same component? */+	  if(neighbour_cell->max_ival == 1)+	    continue;+	  /* Is the neighbour at the same component recursion level? */+	  if(p.cr_get_level(neighbour_cell->first) != level)+	    continue;++	  if(neighbour_cell->max_ival_count == 0)+	    neighbour_heap.insert(neighbour_cell->first);+	  neighbour_cell->max_ival_count++;+	}+      while(!neighbour_heap.is_empty())+	{+	  const unsigned int start = neighbour_heap.remove();+	  Partition::Cell* const neighbour_cell =+	    p.get_cell(p.elements[start]);+	  +	  /* Skip saturated neighbour cells */+	  if(neighbour_cell->max_ival_count == neighbour_cell->length)+	    {+	      neighbour_cell->max_ival_count = 0;+	      continue;+	    } +	  neighbour_cell->max_ival_count = 0;+	  neighbour_cell->max_ival = 1;+	  component.push_back(neighbour_cell);+	}++      ei = v.edges_in.begin();+      for(unsigned int j = v.nof_edges_in(); j > 0; j--)+	{+	  const unsigned int neighbour = *ei++;+	  +	  Partition::Cell* const neighbour_cell = p.get_cell(neighbour);++	  /* Skip unit neighbours */+	  if(neighbour_cell->is_unit())+	    continue;+	  /* Already marked to be in the same component? */+	  if(neighbour_cell->max_ival == 1)+	    continue;+	  /* Is the neighbour at the same component recursion level? */+	  if(p.cr_get_level(neighbour_cell->first) != level)+	    continue;++	  if(neighbour_cell->max_ival_count == 0)+	    neighbour_heap.insert(neighbour_cell->first);+	  neighbour_cell->max_ival_count++;+	}+      while(!neighbour_heap.is_empty())+	{+	  const unsigned int start = neighbour_heap.remove();+	  Partition::Cell* const neighbour_cell =+	    p.get_cell(p.elements[start]);+	  +	  /* Skip saturated neighbour cells */+	  if(neighbour_cell->max_ival_count == neighbour_cell->length)+	    {+	      neighbour_cell->max_ival_count = 0;+	      continue;+	    } +	  neighbour_cell->max_ival_count = 0;+	  neighbour_cell->max_ival = 1;+	  component.push_back(neighbour_cell);+	}+    }++  for(unsigned int i = 0; i < component.size(); i++)+    {+      Partition::Cell* const cell = component[i];+      cell->max_ival = 0;+      cr_component.push_back(cell->first);+      cr_component_elements += cell->length;+    }++  if(verbstr and verbose_level > 2) {+    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",+	    (long unsigned)cr_component.size(), cr_component_elements);+    fflush(verbstr);+  }++  return true;+}++++++bool+Digraph::nucr_find_first_component(const unsigned int level,+				 std::vector<unsigned int>& component,+				 unsigned int& component_elements,+				 Partition::Cell*& sh_return)+{++  component.clear();+  component_elements = 0;+  sh_return = 0;+  unsigned int sh_first  = 0;+  unsigned int sh_size   = 0;+  unsigned int sh_nuconn = 0;++  /* Find first non-discrete cell in the component level */+  Partition::Cell* first_cell = p.first_nonsingleton_cell;+  while(first_cell)+    {+      if(p.cr_get_level(first_cell->first) == level)+	break;+      first_cell = first_cell->next_nonsingleton;+    }++  if(!first_cell)+    {+      /* The component is discrete, return false */+      return false;+    }+	+  std::vector<Partition::Cell*> comp;+  KStack<Partition::Cell*> neighbours;+  neighbours.init(get_nof_vertices());++  first_cell->max_ival = 1;+  comp.push_back(first_cell);++  for(unsigned int i = 0; i < comp.size(); i++)+    {+      Partition::Cell* const cell = comp[i];++      unsigned int nuconn = 1;++      const Vertex& v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei;++      /*| Phase 1: outgoing edges */+      ei = v.edges_out.begin();+      for(unsigned int j = v.nof_edges_out(); j > 0; j--)+	{+	  const unsigned int neighbour = *ei++;+	  +	  Partition::Cell* const neighbour_cell = p.get_cell(neighbour);++	  /* Skip unit neighbours */+	  if(neighbour_cell->is_unit())+	    continue;+	  /* Is the neighbour at the same component recursion level? */+	  //if(p.cr_get_level(neighbour_cell->first) != level)+	  //  continue;+	  if(neighbour_cell->max_ival_count == 0)+	    neighbours.push(neighbour_cell);+	  neighbour_cell->max_ival_count++;+	}+      while(!neighbours.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbours.pop();+	  /* Skip saturated neighbour cells */+	  if(neighbour_cell->max_ival_count == neighbour_cell->length)+	    {+	      neighbour_cell->max_ival_count = 0;+	      continue;+	    }+	  nuconn++;+	  neighbour_cell->max_ival_count = 0;+	  if(neighbour_cell->max_ival == 0) {+	    comp.push_back(neighbour_cell);+	    neighbour_cell->max_ival = 1;+	  }+	}++      /*| Phase 2: incoming edges */+      ei = v.edges_in.begin();+      for(unsigned int j = v.nof_edges_in(); j > 0; j--)+	{+	  const unsigned int neighbour = *ei++;+	  Partition::Cell* const neighbour_cell = p.get_cell(neighbour);+	  /*| Skip unit neighbours */+	  if(neighbour_cell->is_unit())+	    continue;+	  /* Is the neighbour at the same component recursion level? */+	  //if(p.cr_get_level(neighbour_cell->first) != level)+	  //  continue;+	  if(neighbour_cell->max_ival_count == 0)+	    neighbours.push(neighbour_cell);+	  neighbour_cell->max_ival_count++;+	}+      while(!neighbours.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbours.pop();+	  /* Skip saturated neighbour cells */+	  if(neighbour_cell->max_ival_count == neighbour_cell->length)+	    {+	      neighbour_cell->max_ival_count = 0;+	      continue;+	    }+	  nuconn++;+	  neighbour_cell->max_ival_count = 0;+	  if(neighbour_cell->max_ival == 0) {+	    comp.push_back(neighbour_cell);+	    neighbour_cell->max_ival = 1;+	  }+	}++      /*| Phase 3: splitting heuristics */+      switch(sh) {+      case shs_f:+	if(sh_return == 0 or+	   cell->first <= sh_first) {+	  sh_return = cell;+	  sh_first = cell->first;+	}+	break;+      case shs_fs:+	if(sh_return == 0 or+	   cell->length < sh_size or+	   (cell->length == sh_size and cell->first <= sh_first)) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	}+	break;+      case shs_fl:+	if(sh_return == 0 or+	   cell->length > sh_size or+	   (cell->length == sh_size and cell->first <= sh_first)) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	}+	break;+      case shs_fm:+	if(sh_return == 0 or+	   nuconn > sh_nuconn or+	   (nuconn == sh_nuconn and cell->first <= sh_first)) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_nuconn = nuconn;+	}+	break;+      case shs_fsm:+	if(sh_return == 0 or+	   nuconn > sh_nuconn or+	   (nuconn == sh_nuconn and+	    (cell->length < sh_size or+	     (cell->length == sh_size and cell->first <= sh_first)))) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	  sh_nuconn = nuconn;+	}+	break;+      case shs_flm:+	if(sh_return == 0 or+	   nuconn > sh_nuconn or+	   (nuconn == sh_nuconn and+	    (cell->length > sh_size or+	     (cell->length == sh_size and cell->first <= sh_first)))) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	  sh_nuconn = nuconn;+	}+	break;+      default:+	fatal_error("Internal error - unknown splitting heuristics");+	return 0;+      }+    }+  assert(sh_return);++  for(unsigned int i = 0; i < comp.size(); i++)+    {+      Partition::Cell* const cell = comp[i];+      cell->max_ival = 0;+      component.push_back(cell->first);+      component_elements += cell->length;+    }++  if(verbstr and verbose_level > 2) {+    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",+	    (long unsigned)component.size(), component_elements);+    fflush(verbstr);+  }++  return true;+}+++++/*-------------------------------------------------------------------------+ *+ * Routines for undirected graphs+ *+ *-------------------------------------------------------------------------*/++Graph::Vertex::Vertex()+{+  color = 0;+}+++Graph::Vertex::~Vertex()+{+  ;+}+++void+Graph::Vertex::add_edge(const unsigned int other_vertex)+{+  edges.push_back(other_vertex);+}+++void+Graph::Vertex::remove_duplicate_edges(std::vector<bool>& tmp)+{+#if defined(BLISS_CONSISTENCY_CHECKS)+  /* Pre-conditions  */+  for(unsigned int i = 0; i < tmp.size(); i++) assert(tmp[i] == false);+#endif+  for(std::vector<unsigned int>::iterator iter = edges.begin();+      iter != edges.end(); )+    {+      const unsigned int dest_vertex = *iter;+      if(tmp[dest_vertex] == true)+	{+	  /* A duplicate edge found! */+	  iter = edges.erase(iter);+	}+      else+	{+	  /* Not seen earlier, mark as seen */+	  tmp[dest_vertex] = true;+	  iter++;+	}+    }++  /* Clear tmp */+  for(std::vector<unsigned int>::iterator iter = edges.begin();+      iter != edges.end();+      iter++)+    {+      tmp[*iter] = false;+    }+#if defined(BLISS_CONSISTENCY_CHECKS)+  /* Post-conditions  */+  for(unsigned int i = 0; i < tmp.size(); i++) assert(tmp[i] == false);+#endif+}+++/**+ * Sort the edges leaving the vertex according to+ * the vertex number of the other edge end.+ * Time complexity: O(e log(e)), where e is the number of edges+ * leaving the vertex.+ */+void+Graph::Vertex::sort_edges()+{+  std::sort(edges.begin(), edges.end());+}++++/*-------------------------------------------------------------------------+ *+ * Constructor and destructor for undirected graphs+ *+ *-------------------------------------------------------------------------*/+++Graph::Graph(const unsigned int nof_vertices)+{+  vertices.resize(nof_vertices);+  sh = shs_flm;+}+++Graph::~Graph()+{+  ;+}+++unsigned int+Graph::add_vertex(const unsigned int color)+{+  const unsigned int vertex_num = vertices.size();+  vertices.resize(vertex_num + 1);+  vertices.back().color = color;+  return vertex_num;+}+++void+Graph::add_edge(const unsigned int vertex1, const unsigned int vertex2)+{+  //fprintf(stderr, "(%u,%u) ", vertex1, vertex2);+  vertices[vertex1].add_edge(vertex2);+  vertices[vertex2].add_edge(vertex1);+}+++void+Graph::change_color(const unsigned int vertex, const unsigned int color)+{+  vertices[vertex].color = color;+}++++++/*-------------------------------------------------------------------------+ *+ * Read graph in the DIMACS format.+ * Returns 0 if an error occurred.+ *+ *-------------------------------------------------------------------------*/++Graph*+Graph::read_dimacs(FILE* const fp, FILE* const errstr)+{+  Graph *g = 0;+  unsigned int nof_vertices;+  unsigned int nof_edges;+  unsigned int line_num = 1;+  int c;++  const bool verbose = false;+  FILE* const verbstr = stdout;+  +  /* Read comments and the problem definition line */+  while(1)+    {+      c = getc(fp);+      if(c == 'c')+	{+	  /* A comment, ignore the rest of the line */+	  while((c = getc(fp)) != '\n')+	    {+	      if(c == EOF)+		{+		  if(errstr)+		    fprintf(errstr,+			    "error in line %u: not in DIMACS format\n",+			    line_num);+		  goto error_exit;+		}+	    }+	  line_num++;+	  continue;+	}+      if(c == 'p')+	{+	  /* The problem definition line */+	  if(fscanf(fp, " edge %u %u\n", &nof_vertices, &nof_edges) != 2)+	    {+	      if(errstr)+		fprintf(errstr, "error in line %u: not in DIMACS format\n",+			line_num);+	      goto error_exit;+	    }+	  line_num++;+	  break;+	}+      if(errstr)+	fprintf(errstr, "error in line %u: not in DIMACS format\n", line_num);+      goto error_exit;+    }+  +  if(nof_vertices <= 0)+    {+      if(errstr)+	fprintf(errstr, "error: no vertices\n");+      goto error_exit;+    }+  if(verbose)+    {+      fprintf(verbstr, "Instance has %d vertices and %d edges\n",+	      nof_vertices, nof_edges);+      fflush(verbstr);+    }++  g = new Graph(nof_vertices);++  //+  // Read vertex colors+  //+  if(verbose)+    {+      fprintf(verbstr, "Reading vertex colors...\n");+      fflush(verbstr);+    }+  while(1)+    {+      c = getc(fp);+      if(c != 'n')+	{+	  ungetc(c, fp);+	  break;+	}+      ungetc(c, fp);+      unsigned int vertex;+      unsigned int color;+      if(fscanf(fp, "n %u %u\n", &vertex, &color) != 2)+	{+	  if(errstr)+	    fprintf(errstr, "error in line %u: not in DIMACS format\n",+		    line_num);+	  goto error_exit;+	}+      if(!((vertex >= 1) && (vertex <= nof_vertices)))+	{+	  if(errstr)+	    fprintf(errstr,+		    "error in line %u: vertex %u not in range [1,...,%u]\n",+		    line_num, vertex, nof_vertices);+	  goto error_exit;+	}+      line_num++;+      g->change_color(vertex - 1, color);+    }+  if(verbose)+    {+      fprintf(verbstr, "Done\n");+      fflush(verbstr);+    }++  //+  // Read edges+  //+  if(verbose)+    {+      fprintf(verbstr, "Reading edges...\n");+      fflush(verbstr);+    }+  for(unsigned i = 0; i < nof_edges; i++)+    {+      unsigned int from, to;+      if(fscanf(fp, "e %u %u\n", &from, &to) != 2)+	{+	  if(errstr)+	    fprintf(errstr, "error in line %u: not in DIMACS format\n",+		    line_num);+	  goto error_exit;+	}+      if(!((from >= 1) && (from <= nof_vertices)))+	{+	  if(errstr)+	    fprintf(errstr,+		    "error in line %u: vertex %u not in range [1,...,%u]\n",+		    line_num, from, nof_vertices);+	  goto error_exit;+	}+      if(!((to >= 1) && (to <= nof_vertices)))+	{+	  if(errstr)+	    fprintf(errstr,+		    "error in line %u: vertex %u not in range [1,...,%u]\n",+		    line_num, to, nof_vertices);+	  goto error_exit;+	}+      line_num++;+      g->add_edge(from-1, to-1);+    }+  if(verbose)+    {+      fprintf(verbstr, "Done\n");+      fflush(verbstr);+    }++  return g;++ error_exit:+  if(g)+    delete g;+  return 0;++}+++void+Graph::write_dimacs(FILE* const fp)+{+  remove_duplicate_edges();+  sort_edges();++  /* First count the total number of edges */+  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++;+	}+    }++  /* Output the "header" line */+  fprintf(fp, "p edge %u %u\n", get_nof_vertices(), nof_edges);++  /* Print the color of each vertex */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      Vertex &v = vertices[i];+      fprintf(fp, "n %u %u\n", i+1, v.color);+      /*+      if(v.color != 0)+	{+	  fprintf(fp, "n %u %u\n", i+1, v.color);+	}+      */+    }++  /* Print the edges */+  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);+	}+    }+}++++void+Graph::sort_edges()+{+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    vertices[i].sort_edges();+}+++int+Graph::cmp(Graph& other)+{+  /* Compare the numbers of vertices */+  if(get_nof_vertices() < other.get_nof_vertices())+    return -1;+  if(get_nof_vertices() > other.get_nof_vertices())+    return 1;+  /* Compare vertex colors */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      if(vertices[i].color < other.vertices[i].color)+	return -1;+      if(vertices[i].color > other.vertices[i].color)+	return 1;+    }+  /* Compare vertex degrees */+  remove_duplicate_edges();+  other.remove_duplicate_edges();+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      if(vertices[i].nof_edges() < other.vertices[i].nof_edges())+	return -1;+      if(vertices[i].nof_edges() > other.vertices[i].nof_edges())+	return 1;+    }+  /* Compare edges */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      Vertex &v1 = vertices[i];+      Vertex &v2 = other.vertices[i];+      v1.sort_edges();+      v2.sort_edges();+      std::vector<unsigned int>::const_iterator ei1 = v1.edges.begin();+      std::vector<unsigned int>::const_iterator ei2 = v2.edges.begin();+      while(ei1 != v1.edges.end())+	{+	  if(*ei1 < *ei2)+	    return -1;+	  if(*ei1 > *ei2)+	    return 1;+	  ei1++;+	  ei2++;+	}+    }+  return 0;+}+++Graph*+Graph::permute(const std::vector<unsigned int>& perm) const+{+#if defined(BLISS_CONSISTENCY_CHECKS)+#endif++  Graph* const g = new Graph(get_nof_vertices());+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      const Vertex& v = vertices[i];+      Vertex& permuted_v = g->vertices[perm[i]];+      permuted_v.color = v.color;+      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]);+	}+      permuted_v.sort_edges();+    }+  return g;+}++Graph*+Graph::permute(const unsigned int* perm) const+{+#if defined(BLISS_CONSISTENCY_CHECKS)+  if(!is_permutation(get_nof_vertices(), perm))+    _INTERNAL_ERROR();+#endif++  Graph* const g = new Graph(get_nof_vertices());+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      const Vertex& v = vertices[i];+      Vertex& permuted_v = g->vertices[perm[i]];+      permuted_v.color = v.color;+      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]);+	}+      permuted_v.sort_edges();+    }+  return g;+}++++++/*-------------------------------------------------------------------------+ *+ * Print graph in graphviz format+ *+ *-------------------------------------------------------------------------*/+++void+Graph::write_dot(const char* const filename)+{+  FILE *fp = fopen(filename, "w");+  if(fp)+    {+      write_dot(fp);+      fclose(fp);+    }+}++void+Graph::write_dot(FILE* const 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.color);+      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");+}+++++++++/*-------------------------------------------------------------------------+ *+ * Get a hash value for the graph.+ *+ *-------------------------------------------------------------------------*/++unsigned int+Graph::get_hash()+{+  remove_duplicate_edges();+  sort_edges();++  UintSeqHash h;++  h.update(get_nof_vertices());++  /* Hash the color of each vertex */+  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      h.update(vertices[i].color);+    }++  /* Hash the edges */+  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;+	  h.update(i);+	  h.update(dest_i);+	}+    }++  return h.get_value();+}++++++void+Graph::remove_duplicate_edges()+{+  std::vector<bool> tmp(vertices.size(), false);++  for(std::vector<Vertex>::iterator vi = vertices.begin();+      vi != vertices.end();+      vi++)+    {+#if defined(BLISS_EXPENSIVE_CONSISTENCY_CHECKS)+      for(unsigned int i = 0; i < tmp.size(); i++) assert(tmp[i] == false);+#endif+      (*vi).remove_duplicate_edges(tmp);+    }+}++++++/*-------------------------------------------------------------------------+ *+ * Partition independent invariants+ *+ *-------------------------------------------------------------------------*/++/*+ * Return the color of the vertex.+ * Time complexity: O(1)+ */+unsigned int+Graph::vertex_color_invariant(const Graph* const g, const unsigned int v)+{+  return g->vertices[v].color;+}++/*+ * Return the degree of the vertex.+ * Time complexity: O(1)+ */+unsigned int+Graph::degree_invariant(const Graph* const g, const unsigned int v)+{+  return g->vertices[v].nof_edges();+}++/*+ * Return 1 if the vertex v has a self-loop, 0 otherwise+ * Time complexity: O(E_v), where E_v is the number of edges leaving v+ */+unsigned int+Graph::selfloop_invariant(const Graph* const g, const unsigned int v)+{+  const Vertex& vertex = g->vertices[v];+  for(std::vector<unsigned int>::const_iterator ei = vertex.edges.begin();+      ei != vertex.edges.end();+      ei++)+    {+      if(*ei == v)+	return 1;+    }+  return 0;+}+++++++/*-------------------------------------------------------------------------+ *+ * Refine the partition p according to a partition independent invariant+ *+ *-------------------------------------------------------------------------*/++bool+Graph::refine_according_to_invariant(unsigned int (*inv)(const Graph* const g,+							 const unsigned int v))+{+  bool refined = false;++  for(Partition::Cell* cell = p.first_nonsingleton_cell; cell; )+    {++      Partition::Cell* const next_cell = cell->next_nonsingleton;++      const unsigned int* ep = p.elements + cell->first;+      for(unsigned int i = cell->length; i > 0; i--, ep++)+	{+	  const 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++;+	    }+	}+      Partition::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+ *+ *-------------------------------------------------------------------------*/++bool+Graph::split_neighbourhood_of_cell(Partition::Cell* const cell)+{+++  const bool was_equal_to_first = refine_equal_to_first;++  if(compute_eqref_hash)+    {+      eqref_hash.update(cell->first);+      eqref_hash.update(cell->length);+    }++  const unsigned int* ep = p.elements + cell->first;+  for(unsigned int i = cell->length; i > 0; i--)+    {+      const Vertex& v = vertices[*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++;+	  Partition::Cell * const neighbour_cell = p.get_cell(dest_vertex);+	  if(neighbour_cell->is_unit())+	    continue;+	  const unsigned int ival = ++p.invariant_values[dest_vertex];+	  if(ival > neighbour_cell->max_ival)+	    {+	      neighbour_cell->max_ival = ival;+	      neighbour_cell->max_ival_count = 1;+	      if(ival == 1) {+		neighbour_heap.insert(neighbour_cell->first);+	      }+	    }+	  else if(ival == neighbour_cell->max_ival) {+	    neighbour_cell->max_ival_count++;+	  }+	}+    }+  +  while(!neighbour_heap.is_empty())+    {+      const unsigned int start = neighbour_heap.remove();+      Partition::Cell * const neighbour_cell = p.get_cell(p.elements[start]);+      +      if(compute_eqref_hash)+	{+	  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);+	}+++      Partition::Cell* const last_new_cell = p.zplit_cell(neighbour_cell, true);++      /* Update certificate and hash if needed */+      const Partition::Cell* c = neighbour_cell;+      while(1)+	{+	  if(in_search)+	    {+	      /* Build certificate */+	      cert_add_redundant(CERT_SPLIT, c->first, c->length);+	      /* No need to continue? */+	      if(refine_compare_certificate and+		 (refine_equal_to_first == false) and+		 (refine_cmp_to_best < 0))+		goto worse_exit;+	    }+	  if(compute_eqref_hash)+	    {+	      eqref_hash.update(c->first);+	      eqref_hash.update(c->length);+	    }+	  if(c == last_new_cell)+	    break;+	  c = c->next;+	}+    }++  if(refine_compare_certificate and+     (refine_equal_to_first == false) and+     (refine_cmp_to_best < 0))+    return true;++  return false;++ worse_exit:+  /* Clear neighbour heap */+  UintSeqHash rest;+  while(!neighbour_heap.is_empty())+    {+      const unsigned int start = neighbour_heap.remove();+      Partition::Cell * const neighbour_cell = p.get_cell(p.elements[start]);+      if(opt_use_failure_recording and was_equal_to_first)+	{+	  rest.update(neighbour_cell->first);+	  rest.update(neighbour_cell->length);+	  rest.update(neighbour_cell->max_ival);+	  rest.update(neighbour_cell->max_ival_count);+	}+      neighbour_cell->max_ival = 0;+      neighbour_cell->max_ival_count = 0;+     p.clear_ivs(neighbour_cell);+    }+  if(opt_use_failure_recording and was_equal_to_first)+    {+      for(unsigned int i = p.splitting_queue.size(); i > 0; i--)+	{+	  Partition::Cell* const cell = p.splitting_queue.pop_front();+	  rest.update(cell->first);+	  rest.update(cell->length);+	  p.splitting_queue.push_back(cell);+	}+      rest.update(failure_recording_fp_deviation);+      failure_recording_fp_deviation = rest.get_value();+    }+ +  return true;+}++++bool+Graph::split_neighbourhood_of_unit_cell(Partition::Cell* const unit_cell)+{+++  const bool was_equal_to_first = refine_equal_to_first;++  if(compute_eqref_hash)+    {+      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++;+      Partition::Cell * const neighbour_cell = p.get_cell(dest_vertex);+      +      if(neighbour_cell->is_unit()) {+	if(in_search) {+	  /* Remember neighbour in order to generate certificate */+	  neighbour_heap.insert(neighbour_cell->first);+	}+	continue;+      }+      if(neighbour_cell->max_ival_count == 0)+	{+	  neighbour_heap.insert(neighbour_cell->first);+	}+      neighbour_cell->max_ival_count++;++      unsigned int * const swap_position =+	p.elements + neighbour_cell->first + neighbour_cell->length -+	neighbour_cell->max_ival_count;+      *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();+      Partition::Cell* neighbour_cell =	p.get_cell(p.elements[start]);++#if defined(BLISS_CONSISTENCY_CHECKS)+      if(neighbour_cell->is_unit()) {+      } else {+      }+#endif++      if(compute_eqref_hash)+	{+	  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 and+	 neighbour_cell->max_ival_count != neighbour_cell->length)+	{+	  Partition::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)+	    {+	      p.element_to_cell_map[*ep] = new_cell;+	      ep++;+	    }+	  neighbour_cell->max_ival_count = 0;+	  +	  +	  if(compute_eqref_hash)+	    {+	      /* 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 */+	  if(neighbour_cell->is_in_splitting_queue()) {+	    /* Both cells must be included in splitting_queue in order+	       to ensure refinement into equitable partition */+	    p.splitting_queue_add(new_cell);+	  } else {+	    Partition::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.splitting_queue_add(min_cell);+	    if(max_cell->is_unit()) {+	      /* Put the "larger" cell also in splitting_queue */+	      p.splitting_queue_add(max_cell);+	    }+	  }+	  /* Update pointer for certificate generation */+	  neighbour_cell = new_cell;+	}+      else+	{+	  /* neighbour_cell->length == 1 ||+	     neighbour_cell->max_ival_count == neighbour_cell->length */+	  neighbour_cell->max_ival_count = 0;+	}+      +      /*+       * Build certificate if required+       */+      if(in_search)+	{+	  for(unsigned int i = neighbour_cell->first,+		j = neighbour_cell->length;+	      j > 0;+	      j--, i++)+	    {+	      /* Build certificate */+	      cert_add(CERT_EDGE, unit_cell->first, i);+	      /* No need to continue? */+	      if(refine_compare_certificate and+		 (refine_equal_to_first == false) and+		 (refine_cmp_to_best < 0))+		goto worse_exit;+	    }+	} /* if(in_search) */+    } /* while(!neighbour_heap.is_empty()) */+  +  if(refine_compare_certificate and+     (refine_equal_to_first == false) and+     (refine_cmp_to_best < 0))+    return true;++  return false;++ worse_exit:+  /* Clear neighbour heap */+  UintSeqHash rest;+  while(!neighbour_heap.is_empty())+    {+      const unsigned int start = neighbour_heap.remove();+      Partition::Cell * const neighbour_cell = p.get_cell(p.elements[start]);+      if(opt_use_failure_recording and was_equal_to_first)+	{+	  rest.update(neighbour_cell->first);+	  rest.update(neighbour_cell->length);+	  rest.update(neighbour_cell->max_ival_count);+	}+      neighbour_cell->max_ival_count = 0;+    }+  if(opt_use_failure_recording and was_equal_to_first)+    {+      rest.update(failure_recording_fp_deviation);+      failure_recording_fp_deviation = rest.get_value();+    }+  return true;+}++++++++++/*-------------------------------------------------------------------------+ *+ * Check whether the current partition p is equitable.+ * Performance: very slow, use only for debugging purposes.+ *+ *-------------------------------------------------------------------------*/++bool Graph::is_equitable() const+{+  const unsigned int N = get_nof_vertices();+  if(N == 0)+    return true;++  std::vector<unsigned int> first_count = std::vector<unsigned int>(N, 0);+  std::vector<unsigned int> other_count = std::vector<unsigned int>(N, 0);++  for(Partition::Cell *cell = p.first_cell; cell; cell = cell->next)+    {+      if(cell->is_unit())+	continue;+      +      unsigned int *ep = p.elements + cell->first;+      const Vertex &first_vertex = vertices[*ep++];++      /* Count how many edges lead from the first vertex to+       * the neighbouring cells */+      for(std::vector<unsigned int>::const_iterator ei =+	    first_vertex.edges.begin();+	  ei != first_vertex.edges.end();+	  ei++)+	{+	  first_count[p.get_cell(*ei)->first]++;+	}++      /* Count and compare to the edges of the other vertices */+      for(unsigned int i = cell->length; i > 1; i--)+	{+	  const Vertex &vertex = vertices[*ep++];+	  for(std::vector<unsigned int>::const_iterator ei =+		vertex.edges.begin();+	      ei != vertex.edges.end();+	      ei++)+	    {+	      other_count[p.get_cell(*ei)->first]++;+	    }+	  for(Partition::Cell *cell2 = p.first_cell;+	      cell2;+	      cell2 = cell2->next)+	    {+	      if(first_count[cell2->first] != other_count[cell2->first])+		{+		  /* Not equitable */+		  return false;+		}+	      other_count[cell2->first] = 0;+	    }+	}+      /* Reset first_count */+      for(unsigned int i = 0; i < N; i++)+	first_count[i] = 0;+    }+  return true;+}++++++/*-------------------------------------------------------------------------+ *+ * Build the initial equitable partition+ *+ *-------------------------------------------------------------------------*/++void Graph::make_initial_equitable_partition()+{+  refine_according_to_invariant(&vertex_color_invariant);+  p.splitting_queue_clear();+  //p.print_signature(stderr); fprintf(stderr, "\n");++  refine_according_to_invariant(&selfloop_invariant);+  p.splitting_queue_clear();+  //p.print_signature(stderr); fprintf(stderr, "\n");++  refine_according_to_invariant(&degree_invariant);+  p.splitting_queue_clear();+  //p.print_signature(stderr); fprintf(stderr, "\n");++  refine_to_equitable();+  //p.print_signature(stderr); fprintf(stderr, "\n");++}++++++++/*-------------------------------------------------------------------------+ *+ * Find the next cell to be splitted+ *+ *-------------------------------------------------------------------------*/+++Partition::Cell*+Graph::find_next_cell_to_be_splitted(Partition::Cell* cell)+{+  switch(sh) {+  case shs_f:   return sh_first();+  case shs_fs:  return sh_first_smallest();+  case shs_fl:  return sh_first_largest();+  case shs_fm:  return sh_first_max_neighbours();+  case shs_fsm: return sh_first_smallest_max_neighbours();+  case shs_flm: return sh_first_largest_max_neighbours();+  default:+    fatal_error("Internal error - unknown splitting heuristics");+    return 0;+  }+}++/** \internal+ * A splitting heuristic.+ * Returns the first nonsingleton cell in the current partition.+ */+Partition::Cell*+Graph::sh_first()+{+  Partition::Cell* best_cell = 0;+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      best_cell = cell;+      break;+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first smallest nonsingleton cell in the current partition.+ */+Partition::Cell*+Graph::sh_first_smallest()+{+  Partition::Cell* best_cell = 0;+  unsigned int best_size = UINT_MAX;+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      if(cell->length < best_size)+	{+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first largest nonsingleton cell in the current partition.+ */+Partition::Cell*+Graph::sh_first_largest()+{+  Partition::Cell* best_cell = 0;+  unsigned int best_size = 0;+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      if(cell->length > best_size)+	{+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first nonsingleton cell with max number of neighbouring+ *   nonsingleton cells.+ * Assumes that the partition p is equitable.+ * Assumes that the max_ival fields of the cells are all 0.+ */+Partition::Cell*+Graph::sh_first_max_neighbours()+{+  Partition::Cell* best_cell = 0;+  int best_value = -1;+  KStack<Partition::Cell*> neighbour_cells_visited;+  neighbour_cells_visited.init(get_nof_vertices());+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {+      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      const Vertex& v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei = v.edges.begin();+      for(unsigned int j = v.nof_edges(); j > 0; j--)+	{+	  Partition::Cell * const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      int value = 0;+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}+      if(value > best_value)+	{+	  best_value = value;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first smallest nonsingleton cell with max number of neighbouring+ * nonsingleton cells.+ * Assumes that the partition p is equitable.+ * Assumes that the max_ival fields of the cells are all 0.+ */+Partition::Cell*+Graph::sh_first_smallest_max_neighbours()+{+  Partition::Cell* best_cell = 0;+  int best_value = -1;+  unsigned int best_size = UINT_MAX;+  KStack<Partition::Cell*> neighbour_cells_visited;+  neighbour_cells_visited.init(get_nof_vertices());+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {++      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+	+      const Vertex& v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei = v.edges.begin();+      for(unsigned int j = v.nof_edges(); j > 0; j--)+	{+	  Partition::Cell* const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      int value = 0;+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}+      if((value > best_value) or+	 (value == best_value and cell->length < best_size))+	{+	  best_value = value;+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}++/** \internal+ * A splitting heuristic.+ * Returns the first largest nonsingleton cell with max number of neighbouring+ * nonsingleton cells.+ * Assumes that the partition p is equitable.+ * Assumes that the max_ival fields of the cells are all 0.+ */+Partition::Cell*+Graph::sh_first_largest_max_neighbours()+{+  Partition::Cell* best_cell = 0;+  int best_value = -1;+  unsigned int best_size = 0;+  KStack<Partition::Cell*> neighbour_cells_visited;+  neighbour_cells_visited.init(get_nof_vertices());+  for(Partition::Cell* cell = p.first_nonsingleton_cell;+      cell;+      cell = cell->next_nonsingleton)+    {++      if(opt_use_comprec and p.cr_get_level(cell->first) != cr_level)+	continue;+      const Vertex& v = vertices[p.elements[cell->first]];+      std::vector<unsigned int>::const_iterator ei = v.edges.begin();+      for(unsigned int j = v.nof_edges(); j > 0; j--)+	{+	  Partition::Cell* const neighbour_cell = p.get_cell(*ei++);+	  if(neighbour_cell->is_unit())+	    continue;+	  neighbour_cell->max_ival++;+	  if(neighbour_cell->max_ival == 1)+	    neighbour_cells_visited.push(neighbour_cell);+	}+      int value = 0;+      while(!neighbour_cells_visited.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbour_cells_visited.pop();+	  if(neighbour_cell->max_ival != neighbour_cell->length)+	    value++;+	  neighbour_cell->max_ival = 0;+	}+      if((value > best_value) or+	 (value == best_value and cell->length > best_size))+	{+	  best_value = value;+	  best_size = cell->length;+	  best_cell = cell;+	}+    }+  return best_cell;+}+++++++++++++++++++++/*-------------------------------------------------------------------------+ *+ * Initialize the certificate size and memory+ *+ *-------------------------------------------------------------------------*/++void+Graph::initialize_certificate()+{+  certificate_index = 0;+  certificate_current_path.clear();+  certificate_first_path.clear();+  certificate_best_path.clear();+}++++++/*-------------------------------------------------------------------------+ *+ * Check whether perm is an automorphism.+ * Slow, mainly for debugging and validation purposes.+ *+ *-------------------------------------------------------------------------*/++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;++#if defined(BLISS_CONSISTENCY_CHECKS)+  if(!is_permutation(get_nof_vertices(), perm))+    _INTERNAL_ERROR();+#endif++  for(unsigned int i = 0; i < get_nof_vertices(); 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))+	return false;+    }++  return true;+}+++++bool+Graph::is_automorphism(const std::vector<unsigned int>& perm) const+{++  if(!(perm.size() == get_nof_vertices() and is_permutation(perm)))+    return false;++  std::set<unsigned int, std::less<unsigned int> > edges1;+  std::set<unsigned int, std::less<unsigned int> > edges2;++  for(unsigned int i = 0; i < get_nof_vertices(); i++)+    {+      const Vertex& v1 = vertices[i];+      edges1.clear();+      for(std::vector<unsigned int>::const_iterator ei = v1.edges.begin();+	  ei != v1.edges.end();+	  ei++)+	edges1.insert(perm[*ei]);+      +      const Vertex& v2 = vertices[perm[i]];+      edges2.clear();+      for(std::vector<unsigned int>::const_iterator ei = v2.edges.begin();+	  ei != v2.edges.end();+	  ei++)+	edges2.insert(*ei);++      if(!(edges1 == edges2))+	return false;+    }++  return true;+}++++++++bool+Graph::nucr_find_first_component(const unsigned int level)+{++  cr_component.clear();+  cr_component_elements = 0;++  /* Find first non-discrete cell in the component level */+  Partition::Cell* first_cell = p.first_nonsingleton_cell;+  while(first_cell)+    {+      if(p.cr_get_level(first_cell->first) == level)+	break;+      first_cell = first_cell->next_nonsingleton;+    }++  /* The component is discrete, return false */+  if(!first_cell)+    return false;+	+  std::vector<Partition::Cell*> component;+  first_cell->max_ival = 1;+  component.push_back(first_cell);++  for(unsigned int i = 0; i < component.size(); i++)+    {+      Partition::Cell* const cell = component[i];+	  +      const Vertex& v = vertices[p.elements[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 neighbour = *ei++;+	  +	  Partition::Cell* const neighbour_cell = p.get_cell(neighbour);++	  /* Skip unit neighbours */+	  if(neighbour_cell->is_unit())+	    continue;+	  /* Already marked to be in the same component? */+	  if(neighbour_cell->max_ival == 1)+	    continue;+	  /* Is the neighbour at the same component recursion level? */+	  if(p.cr_get_level(neighbour_cell->first) != level)+	    continue;++	  if(neighbour_cell->max_ival_count == 0)+	    neighbour_heap.insert(neighbour_cell->first);+	  neighbour_cell->max_ival_count++;+	}+      while(!neighbour_heap.is_empty())+	{+	  const unsigned int start = neighbour_heap.remove();+	  Partition::Cell* const neighbour_cell =+	    p.get_cell(p.elements[start]);+	  +	  /* Skip saturated neighbour cells */+	  if(neighbour_cell->max_ival_count == neighbour_cell->length)+	    {+	      neighbour_cell->max_ival_count = 0;+	      continue;+	    } +	  neighbour_cell->max_ival_count = 0;+	  neighbour_cell->max_ival = 1;+	  component.push_back(neighbour_cell);+	}+    }++  for(unsigned int i = 0; i < component.size(); i++)+    {+      Partition::Cell* const cell = component[i];+      cell->max_ival = 0;+      cr_component.push_back(cell->first);+      cr_component_elements += cell->length;+    }++  if(verbstr and verbose_level > 2) {+    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",+	    (long unsigned)cr_component.size(), cr_component_elements);+    fflush(verbstr);+  }++  return true;+}+++++bool+Graph::nucr_find_first_component(const unsigned int level,+				 std::vector<unsigned int>& component,+				 unsigned int& component_elements,+				 Partition::Cell*& sh_return)+{++  component.clear();+  component_elements = 0;+  sh_return = 0;+  unsigned int sh_first  = 0;+  unsigned int sh_size   = 0;+  unsigned int sh_nuconn = 0;++  /* Find first non-discrete cell in the component level */+  Partition::Cell* first_cell = p.first_nonsingleton_cell;+  while(first_cell)+    {+      if(p.cr_get_level(first_cell->first) == level)+	break;+      first_cell = first_cell->next_nonsingleton;+    }++  if(!first_cell)+    {+      /* The component is discrete, return false */+      return false;+    }++  std::vector<Partition::Cell*> comp;+  KStack<Partition::Cell*> neighbours;+  neighbours.init(get_nof_vertices());++  first_cell->max_ival = 1;+  comp.push_back(first_cell);++  for(unsigned int i = 0; i < comp.size(); i++)+    {+      Partition::Cell* const cell = comp[i];++      const Vertex& v = vertices[p.elements[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 neighbour = *ei++;+	  +	  Partition::Cell* const neighbour_cell = p.get_cell(neighbour);++	  /* Skip unit neighbours */+	  if(neighbour_cell->is_unit())+	    continue;+	  /* Is the neighbour at the same component recursion level? */+	  //if(p.cr_get_level(neighbour_cell->first) != level)+	  //  continue;+	  if(neighbour_cell->max_ival_count == 0)+	    neighbours.push(neighbour_cell);+	  neighbour_cell->max_ival_count++;+	}+      unsigned int nuconn = 1;+      while(!neighbours.is_empty())+	{+	  Partition::Cell* const neighbour_cell = neighbours.pop();+	  //neighbours.pop_back();+	  +	  /* Skip saturated neighbour cells */+	  if(neighbour_cell->max_ival_count == neighbour_cell->length)+	    {+	      neighbour_cell->max_ival_count = 0;+	      continue;+	    }+	  nuconn++;+	  neighbour_cell->max_ival_count = 0;+	  if(neighbour_cell->max_ival == 0) {+	    comp.push_back(neighbour_cell);+	    neighbour_cell->max_ival = 1;+	  }+	}++      switch(sh) {+      case shs_f:+	if(sh_return == 0 or+	   cell->first <= sh_first) {+	  sh_return = cell;+	  sh_first = cell->first;+	}+	break;+      case shs_fs:+	if(sh_return == 0 or+	   cell->length < sh_size or+	   (cell->length == sh_size and cell->first <= sh_first)) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	}+	break;+      case shs_fl:+	if(sh_return == 0 or+	   cell->length > sh_size or+	   (cell->length == sh_size and cell->first <= sh_first)) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	}+	break;+      case shs_fm:+	if(sh_return == 0 or+	   nuconn > sh_nuconn or+	   (nuconn == sh_nuconn and cell->first <= sh_first)) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_nuconn = nuconn;+	}+	break;+      case shs_fsm:+	if(sh_return == 0 or+	   nuconn > sh_nuconn or+	   (nuconn == sh_nuconn and+	    (cell->length < sh_size or+	     (cell->length == sh_size and cell->first <= sh_first)))) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	  sh_nuconn = nuconn;+	}+	break;+      case shs_flm:+	if(sh_return == 0 or+	   nuconn > sh_nuconn or+	   (nuconn == sh_nuconn and+	    (cell->length > sh_size or+	     (cell->length == sh_size and cell->first <= sh_first)))) {+	  sh_return = cell;+	  sh_first = cell->first;+	  sh_size = cell->length;+	  sh_nuconn = nuconn;+	}+	break;+      default:+	fatal_error("Internal error - unknown splitting heuristics");+	return 0;+      }+    }+  assert(sh_return);++  for(unsigned int i = 0; i < comp.size(); i++)+    {+      Partition::Cell* const cell = comp[i];+      cell->max_ival = 0;+      component.push_back(cell->first);+      component_elements += cell->length;+    }++  if(verbstr and verbose_level > 2) {+    fprintf(verbstr, "NU-component with %lu cells and %u vertices\n",+	    (long unsigned)component.size(), component_elements);+    fflush(verbstr);+  }++  return true;+}+++++}
+ igraph/src/gss.c view
@@ -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;+}+
+ igraph/src/h_abs.c view
@@ -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
+ igraph/src/h_dim.c view
@@ -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
+ igraph/src/h_dnnt.c view
@@ -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
+ igraph/src/h_indx.c view
@@ -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
+ igraph/src/h_len.c view
@@ -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
+ igraph/src/h_mod.c view
@@ -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
+ igraph/src/h_nint.c view
@@ -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
+ igraph/src/h_sign.c view
@@ -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
+ igraph/src/hacks.c view
@@ -0,0 +1,54 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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);+}+
+ igraph/src/heap.c view
@@ -0,0 +1,1083 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/hl_ge.c view
@@ -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
+ igraph/src/hl_gt.c view
@@ -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
+ igraph/src/hl_le.c view
@@ -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
+ igraph/src/hl_lt.c view
@@ -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
+ igraph/src/i77vers.c view
@@ -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. */
+ igraph/src/i_abs.c view
@@ -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
+ igraph/src/i_dim.c view
@@ -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
+ igraph/src/i_dnnt.c view
@@ -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
+ igraph/src/i_indx.c view
@@ -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
+ igraph/src/i_len.c view
@@ -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
+ igraph/src/i_mod.c view
@@ -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
+ igraph/src/i_nint.c view
@@ -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
+ igraph/src/i_sign.c view
@@ -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
+ igraph/src/idamax.c view
@@ -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_ */+
+ igraph/src/ieeeck.c view
@@ -0,0 +1,218 @@+/*  -- 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"++/* > \brief \b IEEECK   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download IEEECK + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/ieeeck.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/ieeeck.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/ieeeck.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         INTEGER          FUNCTION IEEECK( ISPEC, ZERO, ONE )   ++         INTEGER            ISPEC   +         REAL               ONE, ZERO   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > IEEECK is called from the ILAENV to verify that Infinity and   +   > possibly NaN arithmetic is safe (i.e. will not trap).   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] ISPEC   +   > \verbatim   +   >          ISPEC is 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.   +   > \endverbatim   +   >   +   > \param[in] ZERO   +   > \verbatim   +   >          ZERO is REAL   +   >          Must contain the value 0.0   +   >          This is passed to prevent the compiler from optimizing   +   >          away this code.   +   > \endverbatim   +   >   +   > \param[in] ONE   +   > \verbatim   +   >          ONE is 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   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+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.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    ===================================================================== */++    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_ */+
+ igraph/src/igraph_buckets.c view
@@ -0,0 +1,198 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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--;+}
+ igraph/src/igraph_cliquer.c view
@@ -0,0 +1,399 @@++#include "igraph_cliquer.h"+#include "igraph_memory.h"+#include "igraph_constants.h"+#include "igraph_interrupt_internal.h"+#include "cliquer/cliquer.h"+#include "config.h"++#include <assert.h>+++/* Call this to allow for interruption in Cliquer callback functions */+#define CLIQUER_ALLOW_INTERRUPTION() \+    { \+        if (igraph_i_interruption_handler) \+            if (igraph_allow_interruption(NULL) != IGRAPH_SUCCESS) { \+                cliquer_interrupted = 1; \+                return FALSE; \+            } \+    }++/* Interruptable Cliquer functions must be wrapped in CLIQUER_INTERRUPTABLE when called */+#define CLIQUER_INTERRUPTABLE(x) \+    { \+        cliquer_interrupted = 0; \+        x; \+        if (cliquer_interrupted) return IGRAPH_INTERRUPTED; \+    }+++/* Nonzero value signals interuption from Cliquer callback function */+static IGRAPH_THREAD_LOCAL int cliquer_interrupted;+++/* For use with IGRAPH_FINALLY */+static void free_clique_list(igraph_vector_ptr_t *vp) {+    igraph_integer_t i, len;+    len = igraph_vector_ptr_size(vp);+    for (i = 0; i < len; ++i) {+        igraph_vector_destroy((igraph_vector_t *) VECTOR(*vp)[i]);+    }+    igraph_vector_ptr_free_all(vp);+}++/* We shall use this option struct for all calls to Cliquer */+static IGRAPH_THREAD_LOCAL clique_options igraph_cliquer_opt = {+    reorder_by_default, NULL, NULL, NULL, NULL, NULL, NULL, 0+};+++/* Convert an igraph graph to a Cliquer graph */+static void igraph_to_cliquer(const igraph_t *ig, graph_t **cg) {+    igraph_integer_t vcount, ecount;+    int i;++    if (igraph_is_directed(ig)) {+        IGRAPH_WARNING("Edge directions are ignored for clique calculations");+    }++    vcount = igraph_vcount(ig);+    ecount = igraph_ecount(ig);++    *cg = graph_new(vcount);++    for (i = 0; i < ecount; ++i) {+        long s, t;+        s = IGRAPH_FROM(ig, i);+        t = IGRAPH_TO(ig, i);+        if (s != t) {+            GRAPH_ADD_EDGE(*cg, s, t);+        }+    }+}+++/* Copy weights to a Cliquer graph */+static int set_weights(const igraph_vector_t *vertex_weights, graph_t *g) {+    int i;++    assert(vertex_weights != NULL);++    if (igraph_vector_size(vertex_weights) != g->n) {+        IGRAPH_ERROR("Invalid vertex weight vector length", IGRAPH_EINVAL);+    }++    for (i = 0; i < g->n; ++i) {+        g->weights[i] = VECTOR(*vertex_weights)[i];+        if (g->weights[i] != VECTOR(*vertex_weights)[i]) {+            IGRAPH_WARNING("Only integer vertex weights are supported; weights will be truncated to their integer parts");+        }+        if (g->weights[i] <= 0) {+            IGRAPH_ERROR("Vertex weights must be positive", IGRAPH_EINVAL);+        }+    }++    return IGRAPH_SUCCESS;+}+++/* Find all cliques. */++static boolean collect_cliques_callback(set_t s, graph_t *g, clique_options *opt) {+    igraph_vector_ptr_t *list;+    igraph_vector_t *clique;+    int i, j;++    CLIQUER_ALLOW_INTERRUPTION();++    list = (igraph_vector_ptr_t *) opt->user_data;+    clique = (igraph_vector_t *) malloc(sizeof(igraph_vector_t));+    igraph_vector_init(clique, set_size(s));++    i = -1; j = 0;+    while ((i = set_return_next(s, i)) >= 0) {+        VECTOR(*clique)[j++] = i;+    }++    igraph_vector_ptr_push_back(list, clique);++    return TRUE;+}++int igraph_i_cliquer_cliques(const igraph_t *graph, igraph_vector_ptr_t *res,+                             igraph_integer_t min_size, igraph_integer_t max_size) {+    graph_t *g;+    igraph_integer_t vcount = igraph_vcount(graph);++    if (vcount == 0) {+        igraph_vector_ptr_clear(res);+        return IGRAPH_SUCCESS;+    }++    if (min_size <= 0) {+        min_size = 1;+    }+    if (max_size <= 0) {+        max_size = 0;+    }++    if (max_size > 0 && max_size < min_size) {+        IGRAPH_ERROR("max_size must not be smaller than min_size", IGRAPH_EINVAL);+    }++    igraph_to_cliquer(graph, &g);+    IGRAPH_FINALLY(graph_free, g);++    igraph_vector_ptr_clear(res);+    igraph_cliquer_opt.user_data = res;+    igraph_cliquer_opt.user_function = &collect_cliques_callback;++    IGRAPH_FINALLY(free_clique_list, res);+    CLIQUER_INTERRUPTABLE(clique_unweighted_find_all(g, min_size, max_size, /* maximal= */ FALSE, &igraph_cliquer_opt));+    IGRAPH_FINALLY_CLEAN(1);++    graph_free(g);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}+++/* Count cliques of each size. */++static boolean count_cliques_callback(set_t s, graph_t *g, clique_options *opt) {+    igraph_vector_t *hist;++    CLIQUER_ALLOW_INTERRUPTION();++    hist = (igraph_vector_t *) opt->user_data;+    VECTOR(*hist)[set_size(s) - 1] += 1;++    return TRUE;+}++int igraph_i_cliquer_histogram(const igraph_t *graph, igraph_vector_t *hist,+                               igraph_integer_t min_size, igraph_integer_t max_size) {+    graph_t *g;+    int i;+    igraph_integer_t vcount = igraph_vcount(graph);++    if (vcount == 0) {+        igraph_vector_clear(hist);+        return IGRAPH_SUCCESS;+    }++    if (min_size <= 0) {+        min_size = 1;+    }+    if (max_size <= 0) {+        max_size = vcount;    /* also used for initial hist vector size, do not set to zero */+    }++    if (max_size < min_size) {+        IGRAPH_ERROR("max_size must not be smaller than min_size", IGRAPH_EINVAL);+    }++    igraph_to_cliquer(graph, &g);+    IGRAPH_FINALLY(graph_free, g);++    igraph_vector_resize(hist, max_size);+    igraph_vector_null(hist);+    igraph_cliquer_opt.user_data = hist;+    igraph_cliquer_opt.user_function = &count_cliques_callback;++    CLIQUER_INTERRUPTABLE(clique_unweighted_find_all(g, min_size, max_size, /* maximal= */ FALSE, &igraph_cliquer_opt));++    for (i = max_size; i > 0; --i)+        if (VECTOR(*hist)[i - 1] > 0) {+            break;+        }+    igraph_vector_resize(hist, i);+    igraph_vector_resize_min(hist);++    graph_free(g);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}+++/* Call function for each clique. */++struct callback_data {+    igraph_clique_handler_t *handler;+    void *arg;+};++static boolean callback_callback(set_t s, graph_t *g, clique_options *opt) {+    igraph_vector_t *clique;+    struct callback_data *cd;+    int i, j;++    CLIQUER_ALLOW_INTERRUPTION();++    cd = (struct callback_data *) opt->user_data;++    clique = (igraph_vector_t *) malloc(sizeof(igraph_vector_t));+    igraph_vector_init(clique, set_size(s));++    i = -1; j = 0;+    while ((i = set_return_next(s, i)) >= 0) {+        VECTOR(*clique)[j++] = i;+    }++    return (*(cd->handler))(clique, cd->arg);+}++int igraph_i_cliquer_callback(const igraph_t *graph,+                              igraph_integer_t min_size, igraph_integer_t max_size,+                              igraph_clique_handler_t *cliquehandler_fn, void *arg) {+    graph_t *g;+    struct callback_data cd;+    igraph_integer_t vcount = igraph_vcount(graph);++    if (vcount == 0) {+        return IGRAPH_SUCCESS;+    }++    if (min_size <= 0) {+        min_size = 1;+    }+    if (max_size <= 0) {+        max_size = 0;+    }++    if (max_size > 0 && max_size < min_size) {+        IGRAPH_ERROR("max_size must not be smaller than min_size", IGRAPH_EINVAL);+    }++    igraph_to_cliquer(graph, &g);+    IGRAPH_FINALLY(graph_free, g);++    cd.handler = cliquehandler_fn;+    cd.arg = arg;+    igraph_cliquer_opt.user_data = &cd;+    igraph_cliquer_opt.user_function = &callback_callback;++    CLIQUER_INTERRUPTABLE(clique_unweighted_find_all(g, min_size, max_size, /* maximal= */ FALSE, &igraph_cliquer_opt));++    graph_free(g);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}+++/* Find weighted cliques in given weight range. */++int igraph_i_weighted_cliques(const igraph_t *graph,+                              const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res,+                              igraph_real_t min_weight, igraph_real_t max_weight, igraph_bool_t maximal) {+    graph_t *g;+    igraph_integer_t vcount = igraph_vcount(graph);++    if (vcount == 0) {+        igraph_vector_ptr_clear(res);+        return IGRAPH_SUCCESS;+    }++    if (min_weight != (int) min_weight) {+        IGRAPH_WARNING("Only integer vertex weights are supported; the minimum weight will be truncated to its integer part");+        min_weight  = (int) min_weight;+    }++    if (max_weight != (int) max_weight) {+        IGRAPH_WARNING("Only integer vertex weights are supported; the maximum weight will be truncated to its integer part");+        max_weight = (int) max_weight;+    }++    if (min_weight <= 0) {+        min_weight = 1;+    }+    if (max_weight <= 0) {+        max_weight = 0;+    }++    if (max_weight > 0 && max_weight < min_weight) {+        IGRAPH_ERROR("max_weight must not be smaller than min_weight", IGRAPH_EINVAL);+    }++    igraph_to_cliquer(graph, &g);+    IGRAPH_FINALLY(graph_free, g);++    IGRAPH_CHECK(set_weights(vertex_weights, g));++    igraph_vector_ptr_clear(res);+    igraph_cliquer_opt.user_data = res;+    igraph_cliquer_opt.user_function = &collect_cliques_callback;++    IGRAPH_FINALLY(free_clique_list, res);+    CLIQUER_INTERRUPTABLE(clique_find_all(g, min_weight, max_weight, maximal, &igraph_cliquer_opt));+    IGRAPH_FINALLY_CLEAN(1);++    graph_free(g);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}+++/* Find largest weighted cliques. */++int igraph_i_largest_weighted_cliques(const igraph_t *graph,+                                      const igraph_vector_t *vertex_weights, igraph_vector_ptr_t *res) {+    graph_t *g;+    igraph_integer_t vcount = igraph_vcount(graph);++    if (vcount == 0) {+        igraph_vector_ptr_clear(res);+        return IGRAPH_SUCCESS;+    }++    igraph_to_cliquer(graph, &g);+    IGRAPH_FINALLY(graph_free, g);++    IGRAPH_CHECK(set_weights(vertex_weights, g));++    igraph_vector_ptr_clear(res);+    igraph_cliquer_opt.user_data = res;+    igraph_cliquer_opt.user_function = &collect_cliques_callback;++    IGRAPH_FINALLY(free_clique_list, res);+    CLIQUER_INTERRUPTABLE(clique_find_all(g, 0, 0, FALSE, &igraph_cliquer_opt));+    IGRAPH_FINALLY_CLEAN(1);++    graph_free(g);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}+++/* Find weight of largest weight clique. */++int igraph_i_weighted_clique_number(const igraph_t *graph,+                                    const igraph_vector_t *vertex_weights, igraph_real_t *res) {+    graph_t *g;+    igraph_integer_t vcount = igraph_vcount(graph);++    if (vcount == 0) {+        *res = 0;+        return IGRAPH_SUCCESS;+    }++    igraph_to_cliquer(graph, &g);+    IGRAPH_FINALLY(graph_free, g);++    IGRAPH_CHECK(set_weights(vertex_weights, g));++    igraph_cliquer_opt.user_function = NULL;++    /* we are not using a callback function, thus this is not interruptable */+    *res = clique_max_weight(g, &igraph_cliquer_opt);++    graph_free(g);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}
+ igraph/src/igraph_error.c view
@@ -0,0 +1,290 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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];++/* Error strings corresponding to each igraph_error_type_t enum value. */+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",+    /* 59 */ "Random walk got stuck",+    /* 60 */ "Search stopped; this error should never be visible to the user, "+    "please report this error along with the steps to reproduce it."+};++const char* igraph_strerror(const int igraph_errno) {+    if (igraph_errno < 0 || igraph_errno >= sizeof(igraph_i_error_strings) / sizeof(char *)) {+        return "Invalid error code; no error string available.";+    }+    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;+}
+ igraph/src/igraph_estack.c view
@@ -0,0 +1,67 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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
+ igraph/src/igraph_fixed_vectorlist.c view
@@ -0,0 +1,80 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/igraph_grid.c view
@@ -0,0 +1,543 @@+/* -*- mode: C -*-  */+/*+   IGraph R package.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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"); */+/*   } */+/* } */
+ igraph/src/igraph_hashtable.c view
@@ -0,0 +1,128 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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);+}
+ igraph/src/igraph_heap.c view
@@ -0,0 +1,64 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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
+ igraph/src/igraph_hrg.cc view
@@ -0,0 +1,1074 @@+/* -*- mode: C++ -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;++    // If we want to start from HRG+    if (start) {+        d->clearDendrograph();+        if (igraph_hrg_size(hrg) != no_of_nodes) {+            delete d;+            IGRAPH_ERROR("Invalid HRG to start from", IGRAPH_EINVAL);+        }+        // Convert the igraph graph+        IGRAPH_CHECK(igraph_i_hrg_getgraph(graph, d));+        d->importDendrogramStructure(hrg);+    } else {+        // Convert the igraph graph+        IGRAPH_CHECK(igraph_i_hrg_getgraph(graph, d));+        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->clearDendrograph();+        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;++    if (start) {+        d->clearDendrograph();+        IGRAPH_CHECK(igraph_i_hrg_getgraph(graph, d));+        d->importDendrogramStructure(hrg);+    } else {+        IGRAPH_CHECK(igraph_i_hrg_getgraph(graph, d));+        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->clearDendrograph();+        // this has cleared the graph as well.... bug?+        IGRAPH_CHECK(igraph_i_hrg_getsimplegraph(graph, d, &sg, num_bins));+        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;+}
+ igraph/src/igraph_hrg_types.cc view
@@ -0,0 +1,3725 @@+// ***********************************************************************+// *** 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@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@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;            // O(m)+        g        = 0;+    }+    if (internal) {+        delete [] internal;     // O(n)+        internal = 0;+    }+    if (leaf)     {+        delete [] leaf;         // O(n)+        leaf     = 0;+    }+    if (d)        {+        delete    d;            // O(n)+        d        = 0;+    }+    if (splithist) {+        delete    splithist;    // potentially long+        splithist = 0;+    }++    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;        // O(n)+        ctree     = 0;+    }+    if (cancestor) {+        delete [] cancestor;    // O(n)+        cancestor = 0;+    }+}++// *********************************************************************++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;           // O(m)+        g        = NULL;+    }+    if (leaf     != NULL) {+        delete [] leaf;        // O(n)+        leaf     = NULL;+    }+    if (internal != NULL) {+        delete [] internal;    // O(n)+        internal = NULL;+    }+    if (d        != NULL) {+        delete    d;        // O(n)+        d           = NULL;+    }+    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;        // O(n)+        leaf      = NULL;+    }+    if (internal  != NULL) {+        delete [] internal;    // O(n)+        internal  = NULL;+    }+    if (d         != NULL) {+        delete d;              // O(n)+        d         = NULL;+    }+    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@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@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;+}++// ***********************************************************************
+ igraph/src/igraph_marked_queue.c view
@@ -0,0 +1,115 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/igraph_psumtree.c view
@@ -0,0 +1,102 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA+   Copyright (C) 2006 Elliot Paquette <Elliot.Paquette05@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_reset(igraph_psumtree_t *t) {+    igraph_vector_fill(&(t->v), 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];+}
+ igraph/src/igraph_set.c view
@@ -0,0 +1,320 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_set_size+ * \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;++    if (right == -1) {+        return 0;    /* the set is empty */+    }++    /* 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 {+            return 1;+        }+    }++    return SET(*set)[left] == e || SET(*set)[right] == 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;+    }+}+
+ igraph/src/igraph_stack.c view
@@ -0,0 +1,89 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_INT+#include "igraph_pmt.h"+#include "stack.pmt"+#include "igraph_pmt_off.h"+#undef BASE_INT++#define BASE_CHAR+#include "igraph_pmt.h"+#include "stack.pmt"+#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);+}++
+ igraph/src/igraph_strvector.c view
@@ -0,0 +1,592 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/igraph_trie.c view
@@ -0,0 +1,391 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/iio.c view
@@ -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
+ igraph/src/iladlc.c view
@@ -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"++/* > \brief \b ILADLC scans a matrix for its last non-zero column.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download ILADLC + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/iladlc.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/iladlc.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/iladlc.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         INTEGER FUNCTION ILADLC( M, N, A, LDA )   ++         INTEGER            M, N, LDA   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > ILADLC scans A for its last non-zero column.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,N)   +   >          The m by n matrix A.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A. LDA >= max(1,M).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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_ */+
+ igraph/src/iladlr.c view
@@ -0,0 +1,135 @@+/*  -- 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"++/* > \brief \b ILADLR scans a matrix for its last non-zero row.   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download ILADLR + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/iladlr.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/iladlr.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/iladlr.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         INTEGER FUNCTION ILADLR( M, N, A, LDA )   ++         INTEGER            M, N, LDA   +         DOUBLE PRECISION   A( LDA, * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > ILADLR scans A for its last non-zero row.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] M   +   > \verbatim   +   >          M is INTEGER   +   >          The number of rows of the matrix A.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is INTEGER   +   >          The number of columns of the matrix A.   +   > \endverbatim   +   >   +   > \param[in] A   +   > \verbatim   +   >          A is DOUBLE PRECISION array, dimension (LDA,N)   +   >          The m by n matrix A.   +   > \endverbatim   +   >   +   > \param[in] LDA   +   > \verbatim   +   >          LDA is INTEGER   +   >          The leading dimension of the array A. LDA >= max(1,M).   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date September 2012   ++   > \ingroup auxOTHERauxiliary   ++    ===================================================================== */+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.4.2) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       September 2012   +++    =====================================================================   +++       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[max(i__,1) + j * a_dim1] == 0. && i__ >= 1) {+		--i__;+	    }+	    ret_val = max(ret_val,i__);+	}+    }+    return ret_val;+} /* igraphiladlr_ */+
+ igraph/src/ilaenv.c view
@@ -0,0 +1,714 @@+/*  -- 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;++/* > \brief \b ILAENV   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download ILAENV + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/ilaenv.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/ilaenv.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/ilaenv.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         INTEGER FUNCTION ILAENV( ISPEC, NAME, OPTS, N1, N2, N3, N4 )   ++         CHARACTER*( * )    NAME, OPTS   +         INTEGER            ISPEC, N1, N2, N3, N4   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] ISPEC   +   > \verbatim   +   >          ISPEC is 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   +   > \endverbatim   +   >   +   > \param[in] NAME   +   > \verbatim   +   >          NAME is CHARACTER*(*)   +   >          The name of the calling subroutine, in either upper case or   +   >          lower case.   +   > \endverbatim   +   >   +   > \param[in] OPTS   +   > \verbatim   +   >          OPTS is 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'.   +   > \endverbatim   +   >   +   > \param[in] N1   +   > \verbatim   +   >          N1 is INTEGER   +   > \endverbatim   +   >   +   > \param[in] N2   +   > \verbatim   +   >          N2 is INTEGER   +   > \endverbatim   +   >   +   > \param[in] N3   +   > \verbatim   +   >          N3 is INTEGER   +   > \endverbatim   +   >   +   > \param[in] N4   +   > \verbatim   +   >          N4 is INTEGER   +   >          Problem dimensions for the subroutine NAME; these may not all   +   >          be required.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >  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 )   +   > \endverbatim   +   >   +    ===================================================================== */+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.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    ===================================================================== */+++    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_ */+
+ igraph/src/ilnw.c view
@@ -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
+ igraph/src/infomap.cc view
@@ -0,0 +1,322 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@physics.umu.se+   homePage: http://www.tp.umu.se/~rosvall/++   It was integrated in igraph by Emmanuel Navarro+   email: navarro@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;+}
+ igraph/src/infomap_FlowGraph.cc view
@@ -0,0 +1,420 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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;+}++
+ igraph/src/infomap_Greedy.cc view
@@ -0,0 +1,612 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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;++        }++    }+}++
+ igraph/src/infomap_Node.cc view
@@ -0,0 +1,70 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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;+    }++}+
+ igraph/src/inquire.c view
@@ -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);+}
+ igraph/src/interrupt.c view
@@ -0,0 +1,46 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/iparmq.c view
@@ -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"++/* > \brief \b IPARMQ   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download IPARMQ + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/iparmq.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/iparmq.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/iparmq.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         INTEGER FUNCTION IPARMQ( ISPEC, NAME, OPTS, N, ILO, IHI, LWORK )   ++         INTEGER            IHI, ILO, ISPEC, LWORK, N   +         CHARACTER          NAME*( * ), OPTS*( * )   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   >      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   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] ISPEC   +   > \verbatim   +   >          ISPEC is 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.)   +   > \endverbatim   +   >   +   > \param[in] NAME   +   > \verbatim   +   >          NAME is character string   +   >               Name of the calling subroutine   +   > \endverbatim   +   >   +   > \param[in] OPTS   +   > \verbatim   +   >          OPTS is character string   +   >               This is a concatenation of the string arguments to   +   >               TTQRE.   +   > \endverbatim   +   >   +   > \param[in] N   +   > \verbatim   +   >          N is integer scalar   +   >               N is the order of the Hessenberg matrix H.   +   > \endverbatim   +   >   +   > \param[in] ILO   +   > \verbatim   +   >          ILO is INTEGER   +   > \endverbatim   +   >   +   > \param[in] IHI   +   > \verbatim   +   >          IHI is INTEGER   +   >               It is assumed that H is already upper triangular   +   >               in rows and columns 1:ILO-1 and IHI+1:N.   +   > \endverbatim   +   >   +   > \param[in] LWORK   +   > \verbatim   +   >          LWORK is integer scalar   +   >               The amount of workspace available.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERauxiliary   ++   > \par Further Details:   +    =====================   +   >   +   > \verbatim   +   >   +   >       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.   +   > \endverbatim   +   >   +    ===================================================================== */+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.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++    ================================================================ */+    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_ */+
+ igraph/src/iterators.c view
@@ -0,0 +1,1917 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/ivout.c view
@@ -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_ */+
+ igraph/src/kolmogorov.c view
@@ -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))));+}
+ igraph/src/l_ge.c view
@@ -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
+ igraph/src/l_gt.c view
@@ -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
+ igraph/src/l_le.c view
@@ -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
+ igraph/src/l_lt.c view
@@ -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
+ igraph/src/lad.c view
@@ -0,0 +1,1665 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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 and free it using IGRAPH_FINALLY+ * when needed */+#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);  \+    }++/* helper to allocate an array of given size and store its address in a+ * pointer array */+#define ALLOC_ARRAY_IN_HISTORY(VAR, SIZE, TYPE, HISTORY) { \+        VAR = igraph_Calloc(SIZE, TYPE);   \+        if (VAR == 0) {                    \+            IGRAPH_ERROR("cannot allocate '" #VAR "' array in LAD isomorphism search", IGRAPH_ENOMEM); \+        }  \+        IGRAPH_FINALLY(igraph_free, VAR);  \+        IGRAPH_CHECK(igraph_vector_ptr_push_back(HISTORY, VAR));  \+        IGRAPH_FINALLY_CLEAN(1);           \+    }++/* ---------------------------------------------------------*/+/* Coming from graph.c                                      */+/* ---------------------------------------------------------*/++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;++    *result = false;++    /* 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 */+                while (u2 != u) { /* update global matching wrt path */+                    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 = false;++    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, igraph_vector_ptr_t *alloc_history) {+    /* if firstSol then search for the first solution; otherwise search+       for all solutions if induced then search for induced subgraphs;+       otherwise search for partial subgraphs+       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_IN_HISTORY(nbVal, Gp->nbVertices, int, alloc_history);+    ALLOC_ARRAY_IN_HISTORY(globalMatching, Gp->nbVertices, int, alloc_history);++    IGRAPH_CHECK(igraph_i_lad_filter(induced, D, Gp, Gt, &result));+    if (!result) {+        /* 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_IN_HISTORY(val, VECTOR(D->nbVal)[minDom], int, alloc_history);+    for (i = 0; i < VECTOR(D->nbVal)[minDom]; i++) {+        val[i] = VECTOR(D->val)[ VECTOR(D->firstVal)[minDom] + i ];+    }++    /* 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,+                                            alloc_history));+        }+        /* 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_vector_ptr_pop_back(alloc_history);++cleanup:+    igraph_free(globalMatching);+    igraph_vector_ptr_pop_back(alloc_history);+    igraph_free(nbVal);+    igraph_vector_ptr_pop_back(alloc_history);++    return 0;+}++/**+ * \section about_lad+ *+ * <para>+ * The LAD algorithm can search for a subgraph in a larger graph, or check+ * if two graphs are isomorphic.+ * See Christine Solnon: AllDifferent-based Filtering for Subgraph+ * Isomorphism. Artificial Intelligence, 174(12-13):850-864, 2010.+ * https://doi.org/10.1016/j.artint.2010.05.002+ * as well as the homepage of the LAD library at http://liris.cnrs.fr/csolnon/LAD.html+ * The implementation in igraph is based on LADv1, but it is+ * modified to use igraph's own memory allocation and error handling.+ * </para>+ *+ * <para>+ * LAD uses the concept of domains to indicate vertex compatibility when matching the+ * pattern graph. Domains can be used to implement matching of colored vertices.+ * </para>+ *+ * <para>+ * LAD works with both directed and undirected graphs. Only simple graphs are supported.+ * </para>+ */++/**+ * \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 LAD 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, 2010.+ * https://doi.org/10.1016/j.artint.2010.05.002+ *+ * \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();+    /* Stack to store memory blocks that are allocated during igraph_i_lad_solve */+    igraph_vector_ptr_t alloc_history;++    if (!iso && !map && !maps) {+        IGRAPH_ERROR("Please give least one of `iso', `map' or `maps'",+                     IGRAPH_EINVAL);+    }++    if (igraph_is_directed(pattern) != igraph_is_directed(target)) {+        IGRAPH_ERROR("Cannot search for a directed pattern in an undirected target "+                     "or vice versa", IGRAPH_EINVAL);+    }+    if (time_limit <= 0) {+        time_limit = INT_MAX;+    }++    if (iso)  {+        *iso = (igraph_vcount(pattern) == 0);+    }+    if (map)  {+        igraph_vector_clear(map);+    }+    if (maps) {+        igraph_vector_ptr_clear(maps);+    }++    if (igraph_vcount(pattern) == 0) {+        /* Special case for empty graphs */+        return IGRAPH_SUCCESS;+    }++    IGRAPH_CHECK(igraph_i_lad_createGraph(pattern, &Gp));+    IGRAPH_CHECK(igraph_i_lad_createGraph(target, &Gt));++    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_vector_ptr_init(&alloc_history, 0));+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &alloc_history);++    IGRAPH_CHECK(igraph_i_lad_solve(time_limit, firstSol, (char) induced, &D,+                                    &Gp, &Gt, &invalidDomain, iso, map, maps,+                                    &nbNodes, &nbFail, &nbSol, &begin,+                                    &alloc_history));++    igraph_vector_ptr_destroy_all(&alloc_history);+    IGRAPH_FINALLY_CLEAN(1);++exit:++    igraph_vector_int_destroy(&D.val);+    igraph_vector_int_destroy(&D.matching);+    IGRAPH_FINALLY_CLEAN(2);++exit2:++    igraph_vector_int_destroy(&D.globalMatchingP);+    igraph_vector_int_destroy(&D.globalMatchingT);+    igraph_vector_int_destroy(&D.nbVal);+    igraph_vector_int_destroy(&D.firstVal);+    igraph_matrix_int_destroy(&D.posInVal);+    igraph_matrix_int_destroy(&D.firstMatch);+    igraph_vector_char_destroy(&D.markedToFilter);+    igraph_vector_int_destroy(&D.toFilter);+    IGRAPH_FINALLY_CLEAN(8);++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;+}
+ igraph/src/lapack.c view
@@ -0,0 +1,954 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 &lt; 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;+    }++    IGRAPH_CHECK(igraph_vector_resize(myvalues, n));++    switch (which) {+    case IGRAPH_LAPACK_DSYEV_ALL:+        range = 'A';+        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_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_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);++    if (info != 0) {+        IGRAPH_ERROR("Invalid argument to dsyevr in workspace query", IGRAPH_EINVAL);+    }++    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 (info != 0) {+        IGRAPH_ERROR("Invalid argument to dsyevr in calculation", IGRAPH_EINVAL);+    }++    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;+}++int igraph_lapack_ddot(const igraph_vector_t *v1, const igraph_vector_t *v2,+                       igraph_real_t *res) {++    int n = igraph_vector_size(v1);+    int one = 1;++    if (igraph_vector_size(v2) != n) {+        IGRAPH_ERROR("Dot product of vectors with different dimensions",+                     IGRAPH_EINVAL);+    }++    *res = igraphddot_(&n, VECTOR(*v1), &one, VECTOR(*v2), &one);++    return 0;+}+
+ igraph/src/layout.c view
@@ -0,0 +1,2421 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R package.+   Copyright (C) 2003-2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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"+#include <stdio.h> /* FIXME */+++/**+ * \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.+ * \param order The order of the vertices on the circle. The vertices+ *        not included here, will be placed at (0,0). Supply+ *        \ref igraph_vss_all() here for all vertices, in the order of+ *        their vertex ids.+ * \return Error code.+ *+ * Time complexity: O(|V|), the+ * number of vertices.+ */++int igraph_layout_circle(const igraph_t *graph, igraph_matrix_t *res,+                         igraph_vs_t order) {++    long int no_of_nodes = igraph_vcount(graph);+    igraph_integer_t vs_size;+    long int i;+    igraph_vit_t vit;++    IGRAPH_CHECK(igraph_vs_size(graph, &order, &vs_size));++    IGRAPH_CHECK(igraph_matrix_resize(res, no_of_nodes, 2));+    igraph_matrix_null(res);++    igraph_vit_create(graph, order, &vit);+    for (i = 0; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit), i++) {+        igraph_real_t phi = 2 * M_PI / vs_size * i;+        int idx = IGRAPH_VIT_GET(vit);+        MATRIX(*res, idx, 0) = cos(phi);+        MATRIX(*res, idx, 1) = sin(phi);+    }+    igraph_vit_destroy(&vit);++    return 0;+}++/**+ * \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;+}++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;++}++int igraph_i_layout_reingold_tilford_unreachable(+    const igraph_t *graph,+    igraph_neimode_t mode,+    long int real_root,+    long int no_of_nodes,+    igraph_vector_t *pnewedges);+int igraph_i_layout_reingold_tilford_unreachable(+    const igraph_t *graph,+    igraph_neimode_t mode,+    long int real_root,+    long int no_of_nodes,+    igraph_vector_t *pnewedges) {++    long int no_of_newedges;+    igraph_vector_t visited;+    long int i, j, n;+    igraph_dqueue_t q = IGRAPH_DQUEUE_NULL;+    igraph_adjlist_t allneis;+    igraph_vector_int_t *neis;++    igraph_vector_resize(pnewedges, 0);++    /* traverse from real_root and see what nodes you cannot reach */+    no_of_newedges = 0;+    IGRAPH_VECTOR_INIT_FINALLY(&visited, no_of_nodes);+    IGRAPH_DQUEUE_INIT_FINALLY(&q, 100);++    IGRAPH_CHECK(igraph_adjlist_init(graph, &allneis, mode));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &allneis);++    /* start from real_root and go BFS */+    IGRAPH_CHECK(igraph_dqueue_push(&q, real_root));+    while (!igraph_dqueue_empty(&q)) {+        long int actnode = (long int) igraph_dqueue_pop(&q);+        neis = igraph_adjlist_get(&allneis, actnode);+        n = igraph_vector_int_size(neis);+        VECTOR(visited)[actnode] = 1;+        for (j = 0; j < n; j++) {+            long int neighbor = (long int) VECTOR(*neis)[j];+            if (!(long int)VECTOR(visited)[neighbor]) {+                IGRAPH_CHECK(igraph_dqueue_push(&q, neighbor));+            }+        }+    }++    for (j = 0; j < no_of_nodes; j++) {+        no_of_newedges += 1 - VECTOR(visited)[j];+    }++    /* if any nodes are unreachable, add edges between them and real_root */+    if (no_of_newedges != 0) {++        igraph_vector_resize(pnewedges, no_of_newedges * 2);+        j = 0;+        for (i = 0; i < no_of_nodes; i++) {+            if (!VECTOR(visited)[i]) {+                if (mode != IGRAPH_IN) {+                    VECTOR(*pnewedges)[2 * j] = real_root;+                    VECTOR(*pnewedges)[2 * j + 1] = i;+                } else {+                    VECTOR(*pnewedges)[2 * j] = i;+                    VECTOR(*pnewedges)[2 * j + 1] = real_root;+                }+                j++;+            }+        }+    }++    igraph_dqueue_destroy(&q);+    igraph_adjlist_destroy(&allneis);+    igraph_vector_destroy(&visited);+    IGRAPH_FINALLY_CLEAN(3);++    return IGRAPH_SUCCESS;+}+++/* 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;+    long int i;+    igraph_vector_t newedges;++    /* 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)+     */++    /* at various steps it might be necessary to add edges to the graph */+    IGRAPH_VECTOR_INIT_FINALLY(&newedges, 0);++    if (!igraph_is_directed(graph)) {+        mode = IGRAPH_ALL;+    }++    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 and mode == out,+       or the first element from every component for directed graphs and mode ==+       in,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 (mode != IGRAPH_ALL) {+            /* look for roots by swimming against the stream */+            mode2 = (mode == IGRAPH_IN) ? IGRAPH_OUT : IGRAPH_IN;++            IGRAPH_CHECK(igraph_topological_sorting(graph, &order, mode2));+            IGRAPH_CHECK(igraph_clusters(graph, &membership, /*csize=*/ 0,+                                         &no_comps, IGRAPH_WEAK));+        } 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));++        /* go backwards and fill the roots vector with indices [1, no_of_nodes]+           The index 0 is used to signal this root has not been found yet:+           all indices are then decreased by one to [0, no_of_nodes - 1] */+        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);+        }++        /* count the rootlevels that are 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) {+            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_resize(&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;++                /* zero-level roots don't get anything special */+                if (rl == 0) {+                    continue;+                }++                /* for each nonzero-level root, add vertices+                   and edges at all levels [1, 2, .., rl]+                   piercing through the graph. If mode=="in"+                   they pierce the other way */+                if (mode != IGRAPH_IN) {+                    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++;+                    }+                } else {+                    VECTOR(newedges)[edgeptr++] = rn;+                    VECTOR(newedges)[edgeptr++] = no_of_nodes;+                    for (j = 0; j < rl - 1; j++) {+                        VECTOR(newedges)[edgeptr++] = no_of_nodes;+                        VECTOR(newedges)[edgeptr++] = no_of_nodes + 1;+                        no_of_nodes++;+                    }+                }++                /* move on to the next root */+                VECTOR(*roots)[i] = no_of_nodes++;+            }++            /* actually add the edges to the graph */+            IGRAPH_CHECK(igraph_add_edges(&extended, &newedges, 0));+        }+    }++    /* We have root vertices now. If one or more nonzero-level roots were+       chosen by the user, we have copied the graph and added a few vertices+       and (directed) edges to connect those floating roots to nonfloating,+       zero-level equivalent roots.++       Below, the function++       igraph_i_layout_reingold_tilford(pextended, res, mode, real_root)++       calculates the actual rt coordinates of the graph. However, for+       simplicity that function requires a connected graph and a single root.+       For directed graphs, it needs not be strongly connected, however all+       nodes must be reachable from the root following the stream (i.e. the+       root must be a "mother vertex").++       So before we call that function we have to make sure the (copied) graph+       satisfies that condition. That requires:+         1. if there is more than one root, defining a single real_root+         2. if a real_root is defined, adding edges to connect all roots to it+         3. ensure real_root is mother of the whole graph. If it is not,+            add shortcut edges from real_root to any disconnected node for now.++      NOTE: 3. could be done better, e.g. by topological sorting of some kind.+      But for now it's ok like this.+    */+    /* if there is only one root, no need for real_root */+    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, we need to make real_root */+    } else {+        long int no_of_newedges;++        /* Make copy of the graph unless it exists already */+        if (pextended == graph) {+            pextended = &extended;+            IGRAPH_CHECK(igraph_copy(&extended, graph));+            IGRAPH_FINALLY(igraph_destroy, &extended);+        }++        /* add real_root to the vertices */+        real_root = no_of_nodes;+        IGRAPH_CHECK(igraph_add_vertices(&extended, 1, 0));+        no_of_nodes++;++        /* add edges from the roots to real_root */+        no_of_newedges = igraph_vector_size(proots);+        igraph_vector_resize(&newedges, no_of_newedges * 2);+        for (i = 0; i < no_of_newedges; i++) {+            VECTOR(newedges)[2 * i] = no_of_nodes - 1;+            VECTOR(newedges)[2 * i + 1] = VECTOR(*proots)[i];+        }++        IGRAPH_CHECK(igraph_add_edges(&extended, &newedges, 0));+    }++    /* prepare edges to unreachable parts of the graph */+    IGRAPH_CHECK(igraph_i_layout_reingold_tilford_unreachable(pextended, mode, real_root, no_of_nodes, &newedges));++    if (igraph_vector_size(&newedges) != 0) {+        /* Make copy of the graph unless it exists already */+        if (pextended == graph) {+            pextended = &extended;+            IGRAPH_CHECK(igraph_copy(&extended, graph));+            IGRAPH_FINALLY(igraph_destroy, &extended);+        }++        IGRAPH_CHECK(igraph_add_edges(&extended, &newedges, 0));+    }+    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);+        }+    }+    if (maxx > minx) {+        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 &amp; 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.+ *+ * </para><para>+ * Warning: if the graph is symmetric to the exchange of two vertices+ * (as is the case with leaves of a tree connecting to the same parent),+ * classical multidimensional scaling may assign the same coordinates to+ * these vertices.+ *+ * \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;+}
+ igraph/src/layout_dh.c view
@@ -0,0 +1,457 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R package.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_layout.h"+#include "igraph_interface.h"+#include "igraph_random.h"+#include "igraph_math.h"++#include <math.h>++igraph_bool_t igraph_i_segments_intersect(float p0_x, float p0_y,+        float p1_x, float p1_y,+        float p2_x, float p2_y,+        float p3_x, float p3_y) {+    float s1_x = p1_x - p0_x;+    float s1_y = p1_y - p0_y;+    float s2_x = p3_x - p2_x;+    float s2_y = p3_y - p2_y;++    float s1, s2, t1, t2, s, t;+    s1 = (-s1_y * (p0_x - p2_x) + s1_x * (p0_y - p2_y));+    s2 = (-s2_x * s1_y + s1_x * s2_y);+    if (s2 == 0) {+        return 0;+    }+    t1 = ( s2_x * (p0_y - p2_y) - s2_y * (p0_x - p2_x));+    t2 = (-s2_x * s1_y + s1_x * s2_y);+    s = s1 / s2;+    t = t1 / t2;++    return s >= 0 && s <= 1 && t >= 0 && t <= 1 ? 1 : 0;+}++float igraph_i_point_segment_dist2(float v_x, float v_y,+                                   float u1_x, float u1_y,+                                   float u2_x, float u2_y) {++    float dx = u2_x - u1_x;+    float dy = u2_y - u1_y;+    float l2 = dx * dx + dy * dy;+    float t, p_x, p_y;+    if (l2 == 0) {+        return (v_x - u1_x) * (v_x - u1_x) + (v_y - u1_y) * (v_y - u1_y);+    }+    t = ((v_x - u1_x) * dx + (v_y - u1_y) * dy) / l2;+    if (t < 0.0) {+        return (v_x - u1_x) * (v_x - u1_x) + (v_y - u1_y) * (v_y - u1_y);+    } else if (t > 1.0) {+        return (v_x - u2_x) * (v_x - u2_x) + (v_y - u2_y) * (v_y - u2_y);+    }+    p_x = u1_x + t * dx;+    p_y = u1_y + t * dy;+    return (v_x - p_x) * (v_x - p_x) + (v_y - p_y) * (v_y - p_y);+}++/**+ * \function igraph_layout_davidson_harel+ * Davidson-Harel layout algorithm+ *+ * This function implements the algorithm by Davidson and Harel,+ * see Ron Davidson, David Harel: Drawing Graphs Nicely Using+ * Simulated Annealing. ACM Transactions on Graphics 15(4),+ * pp. 301-331, 1996.+ *+ * </para><para>+ * The algorithm uses simulated annealing and a sophisticated+ * energy function, which is unfortunately hard to parameterize+ * for different graphs. The original publication did not disclose any+ * parameter values, and the ones below were determined by+ * experimentation.+ *+ * </para><para>+ * The algorithm consists of two phases, an annealing phase, and a+ * fine-tuning phase. There is no simulated annealing in the second+ * phase.+ *+ * </para><para>+ * Our implementation tries to follow the original publication, as+ * much as possible. The only major difference is that coordinates are+ * explicitly kept within the bounds of the rectangle of the layout.+ *+ * \param graph The input graph, edge directions are ignored.+ * \param res A matrix, the result is stored here. It can be used to+ *     supply start coordinates, see \p use_seed.+ * \param use_seed Boolean, whether to use the supplied \p res as+ *     start coordinates.+ * \param maxiter The maximum number of annealing iterations. A+ *     reasonable value for smaller graphs is 10.+ * \param fineiter The number of fine tuning iterations. A reasonable+ *     value is max(10, log2(n)) where n is the number of vertices.+ * \param cool_fact Cooling factor. A reasonable value is 0.75.+ * \param weight_node_dist Weight for the node-node distances+ *     component of the energy function. Reasonable value: 1.0.+ * \param weight_border Weight for the distance from the border+ *     component of the energy function. It can be set to zero, if+ *     vertices are allowed to sit on the border.+ * \param weight_edge_lengths Weight for the edge length component+ *     of the energy function, a reasonable value is the density of+ *     the graph divided by 10.+ * \param weight_edge_crossings Weight for the edge crossing component+ *     of the energy function, a reasonable default is 1 minus the+ *     square root of the density of the graph.+ * \param weight_node_edge_dist Weight for the node-edge distance+ *     component of the energy function. A reasonable value is+ *     1 minus the density, divided by 5.+ * \return Error code.+ *+ * Time complexity: one first phase iteration has time complexity+ * O(n^2+m^2), one fine tuning iteration has time complexity O(mn).+ * Time complexity might be smaller if some of the weights of the+ * components of the energy function are set to zero.+ *+ */++int igraph_layout_davidson_harel(const igraph_t *graph, igraph_matrix_t *res,+                                 igraph_bool_t use_seed, igraph_integer_t maxiter,+                                 igraph_integer_t fineiter, igraph_real_t cool_fact,+                                 igraph_real_t weight_node_dist, igraph_real_t weight_border,+                                 igraph_real_t weight_edge_lengths,+                                 igraph_real_t weight_edge_crossings,+                                 igraph_real_t weight_node_edge_dist) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_integer_t no_edges = igraph_ecount(graph);+    float width = sqrt(no_nodes) * 10, height = width;+    igraph_vector_int_t perm;+    igraph_bool_t fine_tuning = 0;+    igraph_integer_t round, i;+    igraph_vector_float_t try_x, try_y;+    igraph_vector_int_t try_idx;+    float move_radius = width / 2;+    float fine_tuning_factor = 0.01;+    igraph_vector_t neis;+    float min_x = width / 2, max_x = -width / 2, min_y = height / 2, max_y = -height / 2;++    igraph_integer_t no_tries = 30;+    float w_node_dist = weight_node_dist ;          /* 1.0 */+    float w_borderlines = weight_border;            /* 0.0 */+    float w_edge_lengths = weight_edge_lengths;     /* 0.0001; */+    float w_edge_crossings = weight_edge_crossings; /* 1.0 */+    float w_node_edge_dist = weight_node_edge_dist; /* 0.2 */++    if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||+                     igraph_matrix_ncol(res) != 2)) {+        IGRAPH_ERROR("Invalid start position matrix size in "+                     "Davidson-Harel layout", IGRAPH_EINVAL);+    }+    if (maxiter < 0) {+        IGRAPH_ERROR("Number of iterations must be non-negative in "+                     "Davidson-Harel layout", IGRAPH_EINVAL);+    }+    if (fineiter < 0) {+        IGRAPH_ERROR("Number of fine tuning iterations must be non-negative in "+                     "Davidson-Harel layout", IGRAPH_EINVAL);+    }+    if (cool_fact <= 0 || cool_fact >= 1) {+        IGRAPH_ERROR("Cooling factor must be in (0,1) in "+                     "Davidson-Harel layout", IGRAPH_EINVAL);+    }++    if (no_nodes == 0) {+        return 0;+    }++    IGRAPH_CHECK(igraph_vector_int_init_seq(&perm, 0, no_nodes - 1));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &perm);+    IGRAPH_CHECK(igraph_vector_float_init(&try_x, no_tries));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &try_x);+    IGRAPH_CHECK(igraph_vector_float_init(&try_y, no_tries));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &try_y);+    IGRAPH_CHECK(igraph_vector_int_init_seq(&try_idx, 0, no_tries - 1));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &try_idx);+    IGRAPH_VECTOR_INIT_FINALLY(&neis, 100);++    RNG_BEGIN();++    if (!use_seed) {+        IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));+        for (i = 0; i < no_nodes; i++) {+            float x, y;+            x = MATRIX(*res, i, 0) = RNG_UNIF(-width / 2, width / 2);+            y = MATRIX(*res, i, 1) = RNG_UNIF(-height / 2, height / 2);+            if (x < min_x) {+                min_x = x;+            } else if (x > max_x) {+                max_x = x;+            }+            if (y < min_y) {+                min_y = y;+            } else if (y > max_y) {+                max_y = y;+            }+        }+    } else {+        min_x = IGRAPH_INFINITY; max_x = IGRAPH_NEGINFINITY;+        min_y = IGRAPH_INFINITY; max_y = IGRAPH_NEGINFINITY;+        for (i = 0; i < no_nodes; i++) {+            float x = MATRIX(*res, i, 0);+            float y = MATRIX(*res, i, 1);+            if (x < min_x) {+                min_x = x;+            } else if (x > max_x) {+                max_x = x;+            }+            if (y < min_y) {+                min_y = y;+            } else if (y > max_y) {+                max_y = y;+            }+        }+    }++    for (i = 0; i < no_tries; i++) {+        float phi = 2 * M_PI / no_tries * i;+        VECTOR(try_x)[i] = cos(phi);+        VECTOR(try_y)[i] = sin(phi);+    }++    for (round = 0; round < maxiter + fineiter; round++) {+        igraph_integer_t p;+        igraph_vector_int_shuffle(&perm);++        fine_tuning = round >= maxiter;+        if (fine_tuning) {+            float fx = fine_tuning_factor * (max_x - min_x);+            float fy = fine_tuning_factor * (max_y - min_y);+            move_radius = fx < fy ? fx : fy;+        }++        for (p = 0; p < no_nodes; p++) {+            igraph_integer_t t;+            igraph_integer_t v = VECTOR(perm)[p];+            igraph_vector_int_shuffle(&try_idx);++            for (t = 0; t < no_tries; t++) {+                float diff_energy = 0.0;+                int ti = VECTOR(try_idx)[t];++                /* Try moving it */+                float old_x = MATRIX(*res, v, 0);+                float old_y = MATRIX(*res, v, 1);+                float new_x = old_x + move_radius * VECTOR(try_x)[ti];+                float new_y = old_y + move_radius * VECTOR(try_y)[ti];++                if (new_x < -width / 2) {+                    new_x = -width / 2 - 1e-6;+                }+                if (new_x >  width / 2) {+                    new_x =  width / 2 - 1e-6;+                }+                if (new_y < -height / 2) {+                    new_y = -height / 2 - 1e-6;+                }+                if (new_y >  height / 2) {+                    new_y =  height / 2 - 1e-6;+                }++                if (w_node_dist != 0) {+                    igraph_integer_t u;+                    for (u = 0; u < no_nodes; u++) {+                        float odx, ody, odist2, dx, dy, dist2;+                        if (u == v) {+                            continue;+                        }+                        odx = old_x - MATRIX(*res, u, 0);+                        ody = old_y - MATRIX(*res, u, 1);+                        dx = new_x - MATRIX(*res, u, 0);+                        dy = new_y - MATRIX(*res, u, 1);+                        odist2 = odx * odx + ody * ody;+                        dist2 = dx * dx + dy * dy;+                        diff_energy += w_node_dist / dist2 - w_node_dist / odist2;+                    }+                }++                if (w_borderlines != 0) {+                    float odx1 = width / 2 - old_x, odx2 = old_x + width / 2;+                    float ody1 = height / 2 - old_y, ody2 = old_y + height / 2;+                    float dx1 = width / 2 - new_x, dx2 = new_x + width / 2;+                    float dy1 = height / 2 - new_y, dy2 = new_y + height / 2;+                    if (odx1 < 0) {+                        odx1 = 2;+                    } if (odx2 < 0) {+                        odx2 = 2;+                    }+                    if (ody1 < 0) {+                        ody1 = 2;+                    } if (ody2 < 0) {+                        ody2 = 2;+                    }+                    if (dx1 < 0) {+                        dx1 = 2;+                    } if (dx2 < 0) {+                        dx2 = 2;+                    }+                    if (dy1 < 0) {+                        dy1 = 2;+                    } if (dy2 < 0) {+                        dy2 = 2;+                    }+                    diff_energy -= w_borderlines *+                                   (1.0 / (odx1 * odx1) + 1.0 / (odx2 * odx2) ++                                    1.0 / (ody1 * ody1) + 1.0 / (ody2 * ody2));+                    diff_energy += w_borderlines *+                                   (1.0 / (dx1 * dx1) + 1.0 / (dx2 * dx2) ++                                    1.0 / (dy1 * dy1) + 1.0 / (dy2 * dy2));+                }++                if (w_edge_lengths != 0) {+                    igraph_integer_t len, j;+                    igraph_neighbors(graph, &neis, v, IGRAPH_ALL);+                    len = igraph_vector_size(&neis);+                    for (j = 0; j < len; j++) {+                        igraph_integer_t u = VECTOR(neis)[j];+                        float odx = old_x - MATRIX(*res, u, 0);+                        float ody = old_y - MATRIX(*res, u, 1);+                        float odist2 = odx * odx + ody * ody;+                        float dx = new_x - MATRIX(*res, u, 0);+                        float dy = new_y - MATRIX(*res, u, 1);+                        float dist2 = dx * dx + dy * dy;+                        diff_energy += w_edge_lengths * (dist2 - odist2);+                    }+                }++                if (w_edge_crossings != 0) {+                    igraph_integer_t len, j, no = 0;+                    igraph_neighbors(graph, &neis, v, IGRAPH_ALL);+                    len = igraph_vector_size(&neis);+                    for (j = 0; j < len; j++) {+                        igraph_integer_t u = VECTOR(neis)[j];+                        float u_x = MATRIX(*res, u, 0);+                        float u_y = MATRIX(*res, u, 1);+                        igraph_integer_t e;+                        for (e = 0; e < no_edges; e++) {+                            igraph_integer_t u1 = IGRAPH_FROM(graph, e);+                            igraph_integer_t u2 = IGRAPH_TO(graph, e);+                            float u1_x, u1_y, u2_x, u2_y;+                            if (u1 == v || u2 == v || u1 == u || u2 == u) {+                                continue;+                            }+                            u1_x = MATRIX(*res, u1, 0);+                            u1_y = MATRIX(*res, u1, 1);+                            u2_x = MATRIX(*res, u2, 0);+                            u2_y = MATRIX(*res, u2, 1);+                            no -= igraph_i_segments_intersect(old_x, old_y, u_x, u_y,+                                                              u1_x, u1_y, u2_x, u2_y);+                            no += igraph_i_segments_intersect(new_x, new_y, u_x, u_y,+                                                              u1_x, u1_y, u2_x, u2_y);+                        }+                    }+                    diff_energy += w_edge_crossings * no;+                }++                if (w_node_edge_dist != 0 && fine_tuning) {+                    igraph_integer_t e, no;++                    /* All non-incident edges from the moved 'v' */+                    for (e = 0; e < no_edges; e++) {+                        igraph_integer_t u1 = IGRAPH_FROM(graph, e);+                        igraph_integer_t u2 = IGRAPH_TO(graph, e);+                        float u1_x, u1_y, u2_x, u2_y, d_ev;+                        if (u1 == v || u2 == v) {+                            continue;+                        }+                        u1_x = MATRIX(*res, u1, 0);+                        u1_y = MATRIX(*res, u1, 1);+                        u2_x = MATRIX(*res, u2, 0);+                        u2_y = MATRIX(*res, u2, 1);+                        d_ev = igraph_i_point_segment_dist2(old_x, old_y, u1_x, u1_y,+                                                            u2_x, u2_y);+                        diff_energy -= w_node_edge_dist / d_ev;+                        d_ev = igraph_i_point_segment_dist2(new_x, new_y, u1_x, u1_y,+                                                            u2_x, u2_y);+                        diff_energy += w_node_edge_dist / d_ev;+                    }++                    /* All other nodes from all of v's incident edges */+                    igraph_incident(graph, &neis, v, IGRAPH_ALL);+                    no = igraph_vector_size(&neis);+                    for (e = 0; e < no; e++) {+                        igraph_integer_t mye = VECTOR(neis)[e];+                        igraph_integer_t u = IGRAPH_OTHER(graph, mye, v);+                        float u_x = MATRIX(*res, u, 0);+                        float u_y = MATRIX(*res, u, 1);+                        igraph_integer_t w;+                        for (w = 0; w < no_nodes; w++) {+                            float w_x, w_y, d_ev;+                            if (w == v || w == u) {+                                continue;+                            }+                            w_x = MATRIX(*res, w, 0);+                            w_y = MATRIX(*res, w, 1);+                            d_ev = igraph_i_point_segment_dist2(w_x, w_y, old_x,+                                                                old_y, u_x, u_y);+                            diff_energy -= w_node_edge_dist / d_ev;+                            d_ev = igraph_i_point_segment_dist2(w_x, w_y, new_x, new_y,+                                                                u_x, u_y);+                            diff_energy += w_node_edge_dist / d_ev;+                        }+                    }+                } /* w_node_edge_dist != 0 && fine_tuning */++                if (diff_energy < 0 ||+                    (!fine_tuning && RNG_UNIF01() < exp(-diff_energy / move_radius))) {+                    MATRIX(*res, v, 0) = new_x;+                    MATRIX(*res, v, 1) = new_y;+                    if (new_x < min_x) {+                        min_x = new_x;+                    } else if (new_x > max_x) {+                        max_x = new_x;+                    }+                    if (new_y < min_y) {+                        min_y = new_y;+                    } else if (new_y > max_y) {+                        max_y = new_y;+                    }+                }++            } /* t < no_tries */++        } /* p < no_nodes  */++        move_radius *= cool_fact;++    } /* round < maxiter */++    RNG_END();++    igraph_vector_destroy(&neis);+    igraph_vector_int_destroy(&try_idx);+    igraph_vector_float_destroy(&try_x);+    igraph_vector_float_destroy(&try_y);+    igraph_vector_int_destroy(&perm);+    IGRAPH_FINALLY_CLEAN(5);++    return 0;+}
+ igraph/src/layout_fr.c view
@@ -0,0 +1,700 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R package.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_layout.h"+#include "igraph_random.h"+#include "igraph_interface.h"+#include "igraph_components.h"+#include "igraph_types_internal.h"++int igraph_layout_i_fr(const igraph_t *graph,+                       igraph_matrix_t *res,+                       igraph_bool_t use_seed,+                       igraph_integer_t niter,+                       igraph_real_t start_temp,+                       const igraph_vector_t *weight,+                       const igraph_vector_t *minx,+                       const igraph_vector_t *maxx,+                       const igraph_vector_t *miny,+                       const igraph_vector_t *maxy) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_integer_t no_edges = igraph_ecount(graph);+    igraph_integer_t i;+    igraph_vector_float_t dispx, dispy;+    igraph_real_t temp = start_temp;+    igraph_real_t difftemp = start_temp / niter;+    float width = sqrtf(no_nodes), height = width;+    igraph_bool_t conn = 1;+    float C;++    igraph_is_connected(graph, &conn, IGRAPH_WEAK);+    if (!conn) {+        C = no_nodes * sqrtf(no_nodes);+    }++    RNG_BEGIN();++    if (!use_seed) {+        IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t x1 = minx ? VECTOR(*minx)[i] : -width / 2;+            igraph_real_t x2 = maxx ? VECTOR(*maxx)[i] :  width / 2;+            igraph_real_t y1 = miny ? VECTOR(*miny)[i] : -height / 2;+            igraph_real_t y2 = maxy ? VECTOR(*maxy)[i] :  height / 2;+            if (!igraph_finite(x1)) {+                x1 = -sqrt(no_nodes) / 2;+            }+            if (!igraph_finite(x2)) {+                x2 =  sqrt(no_nodes) / 2;+            }+            if (!igraph_finite(y1)) {+                y1 = -sqrt(no_nodes) / 2;+            }+            if (!igraph_finite(y2)) {+                y2 =  sqrt(no_nodes) / 2;+            }+            MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);+            MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);+        }+    }++    IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);+    IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);++    for (i = 0; i < niter; i++) {+        igraph_integer_t v, u, e;++        /* calculate repulsive forces, we have a special version+           for unconnected graphs */+        igraph_vector_float_null(&dispx);+        igraph_vector_float_null(&dispy);+        if (conn) {+            for (v = 0; v < no_nodes; v++) {+                for (u = v + 1; u < no_nodes; u++) {+                    float dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+                    float dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+                    float dlen = dx * dx + dy * dy;++                    if (dlen == 0) {+                        dx = RNG_UNIF01() * 1e-9;+                        dy = RNG_UNIF01() * 1e-9;+                        dlen = dx * dx + dy * dy;+                    }++                    VECTOR(dispx)[v] += dx / dlen;+                    VECTOR(dispy)[v] += dy / dlen;+                    VECTOR(dispx)[u] -= dx / dlen;+                    VECTOR(dispy)[u] -= dy / dlen;+                }+            }+        } else {+            for (v = 0; v < no_nodes; v++) {+                for (u = v + 1; u < no_nodes; u++) {+                    float dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+                    float dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+                    float dlen, rdlen;++                    dlen = dx * dx + dy * dy;+                    if (dlen == 0) {+                        dx = RNG_UNIF(0, 1e-6);+                        dy = RNG_UNIF(0, 1e-6);+                        dlen = dx * dx + dy * dy;+                    }++                    rdlen = sqrt(dlen);++                    VECTOR(dispx)[v] += dx * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispy)[v] += dy * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispx)[u] -= dx * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispy)[u] -= dy * (C - dlen * rdlen) / (dlen * C);+                }+            }+        }++        /* calculate attractive forces */+        for (e = 0; e < no_edges; e++) {+            /* each edges is an ordered pair of vertices v and u */+            igraph_integer_t v = IGRAPH_FROM(graph, e);+            igraph_integer_t u = IGRAPH_TO(graph, e);+            igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+            igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+            igraph_real_t w = weight ? VECTOR(*weight)[e] : 1.0;+            igraph_real_t dlen = sqrt(dx * dx + dy * dy) * w;+            VECTOR(dispx)[v] -= (dx * dlen);+            VECTOR(dispy)[v] -= (dy * dlen);+            VECTOR(dispx)[u] += (dx * dlen);+            VECTOR(dispy)[u] += (dy * dlen);+        }++        /* limit max displacement to temperature t and prevent from+           displacement outside frame */+        for (v = 0; v < no_nodes; v++) {+            igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;+            igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;+            igraph_real_t displen = sqrt(dx * dx + dy * dy);+            igraph_real_t mx = fabs(dx) < temp ? dx : temp;+            igraph_real_t my = fabs(dy) < temp ? dy : temp;+            if (displen > 0) {+                MATRIX(*res, v, 0) += (dx / displen) * mx;+                MATRIX(*res, v, 1) += (dy / displen) * my;+            }+            if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) {+                MATRIX(*res, v, 0) = VECTOR(*minx)[v];+            }+            if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {+                MATRIX(*res, v, 0) = VECTOR(*maxx)[v];+            }+            if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {+                MATRIX(*res, v, 1) = VECTOR(*miny)[v];+            }+            if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {+                MATRIX(*res, v, 1) = VECTOR(*maxy)[v];+            }+        }++        temp -= difftemp;+    }++    RNG_END();++    igraph_vector_float_destroy(&dispx);+    igraph_vector_float_destroy(&dispy);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}++int igraph_layout_i_grid_fr(const igraph_t *graph,+                            igraph_matrix_t *res, igraph_bool_t use_seed,+                            igraph_integer_t niter, igraph_real_t start_temp,+                            const igraph_vector_t *weight, const igraph_vector_t *minx,+                            const igraph_vector_t *maxx, const igraph_vector_t *miny,+                            const igraph_vector_t *maxy) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_integer_t no_edges = igraph_ecount(graph);+    float width = sqrtf(no_nodes), height = width;+    igraph_2dgrid_t grid;+    igraph_vector_float_t dispx, dispy;+    igraph_real_t temp = start_temp;+    igraph_real_t difftemp = start_temp / niter;+    igraph_2dgrid_iterator_t vidit;+    igraph_integer_t i;+    const float cellsize = 2.0;++    RNG_BEGIN();++    if (!use_seed) {+        IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t x1 = minx ? VECTOR(*minx)[i] : -width / 2;+            igraph_real_t x2 = maxx ? VECTOR(*maxx)[i] :  width / 2;+            igraph_real_t y1 = miny ? VECTOR(*miny)[i] : -height / 2;+            igraph_real_t y2 = maxy ? VECTOR(*maxy)[i] :  height / 2;+            if (!igraph_finite(x1)) {+                x1 = -sqrt(no_nodes) / 2;+            }+            if (!igraph_finite(x2)) {+                x2 =  sqrt(no_nodes) / 2;+            }+            if (!igraph_finite(y1)) {+                y1 = -sqrt(no_nodes) / 2;+            }+            if (!igraph_finite(y2)) {+                y2 =  sqrt(no_nodes) / 2;+            }+            MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);+            MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);+        }+    }++    /* make grid */+    IGRAPH_CHECK(igraph_2dgrid_init(&grid, res, -width / 2, width / 2, cellsize,+                                    -height / 2, height / 2, cellsize));+    IGRAPH_FINALLY(igraph_2dgrid_destroy, &grid);++    /* place vertices on grid */+    for (i = 0; i < no_nodes; i++) {+        igraph_2dgrid_add2(&grid, i);+    }++    IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);+    IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);++    for (i = 0; i < niter; i++) {+        igraph_integer_t v, u, e;++        igraph_vector_float_null(&dispx);+        igraph_vector_float_null(&dispy);++        /* repulsion */+        igraph_2dgrid_reset(&grid, &vidit);+        while ( (v = igraph_2dgrid_next(&grid, &vidit) - 1) != -1) {+            while ( (u = igraph_2dgrid_next_nei(&grid, &vidit) - 1) != -1) {+                float dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+                float dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+                float dlen = dx * dx + dy * dy;+                if (dlen < cellsize * cellsize) {+                    VECTOR(dispx)[v] += dx / dlen;+                    VECTOR(dispy)[v] += dy / dlen;+                    VECTOR(dispx)[u] -= dx / dlen;+                    VECTOR(dispy)[u] -= dy / dlen;+                }+            }+        }++        /* attraction */+        for (e = 0; e < no_edges; e++) {+            igraph_integer_t v = IGRAPH_FROM(graph, e);+            igraph_integer_t u = IGRAPH_TO(graph, e);+            igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+            igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+            igraph_real_t w = weight ? VECTOR(*weight)[e] : 1.0;+            igraph_real_t dlen = sqrt(dx * dx + dy * dy) * w;+            VECTOR(dispx)[v] -= (dx * dlen);+            VECTOR(dispy)[v] -= (dy * dlen);+            VECTOR(dispx)[u] += (dx * dlen);+            VECTOR(dispy)[u] += (dy * dlen);+        }++        /* update */+        for (v = 0; v < no_nodes; v++) {+            igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;+            igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;+            igraph_real_t displen = sqrt(dx * dx + dy * dy);+            igraph_real_t mx = fabs(dx) < temp ? dx : temp;+            igraph_real_t my = fabs(dy) < temp ? dy : temp;+            if (displen > 0) {+                MATRIX(*res, v, 0) += (dx / displen) * mx;+                MATRIX(*res, v, 1) += (dy / displen) * my;+            }+            if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) {+                MATRIX(*res, v, 0) = VECTOR(*minx)[v];+            }+            if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {+                MATRIX(*res, v, 0) = VECTOR(*maxx)[v];+            }+            if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {+                MATRIX(*res, v, 1) = VECTOR(*miny)[v];+            }+            if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {+                MATRIX(*res, v, 1) = VECTOR(*maxy)[v];+            }+        }++        temp -= difftemp;+    }++    igraph_vector_float_destroy(&dispx);+    igraph_vector_float_destroy(&dispy);+    igraph_2dgrid_destroy(&grid);+    IGRAPH_FINALLY_CLEAN(3);+    return 0;+}++/**+ * \ingroup layout+ * \function igraph_layout_fruchterman_reingold+ * \brief Places the vertices on a plane according to the Fruchterman-Reingold algorithm.+ *+ * </para><para>+ * This is a force-directed layout, see Fruchterman, T.M.J. and+ * Reingold, E.M.: Graph Drawing by Force-directed Placement.+ * Software -- Practice and Experience, 21/11, 1129--1164,+ * 1991.+ * \param graph Pointer to an initialized graph object.+ * \param res Pointer to an initialized matrix object. This will+ *        contain the result and will be resized as needed.+ * \param use_seed Logical, if true the supplied values in the+ *        \p res argument are used as an initial layout, if+ *        false a random initial layout is used.+ * \param niter The number of iterations to do. A reasonable+ *        default value is 500.+ * \param start_temp Start temperature. This is the maximum amount+ *        of movement alloved along one axis, within one step, for a+ *        vertex. Currently it is decreased linearly to zero during+ *        the iteration.+ * \param grid Whether to use the (fast but less accurate) grid based+ *        version of the algorithm. Possible values: \c+ *        IGRAPH_LAYOUT_GRID, \c IGRAPH_LAYOUT_NOGRID, \c+ *        IGRAPH_LAYOUT_AUTOGRID. The last one uses the grid based+ *        version only for large graphs, currently the ones with+ *        more than 1000 vertices.+ * \param weight Pointer to a vector containing edge weights,+ *        the attraction along the edges will be multiplied by these.+ *        It will be ignored if it is a null-pointer.+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote x \endquote coordinate for every vertex.+ * \param maxx Same as \p minx, but the maximum \quote x \endquote+ *        coordinates.+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote y \endquote coordinate for every vertex.+ * \param maxy Same as \p miny, but the maximum \quote y \endquote+ *        coordinates.+ * \return Error code.+ *+ * Time complexity: O(|V|^2) in each+ * iteration, |V| is the number of+ * vertices in the graph.+ */++int igraph_layout_fruchterman_reingold(const igraph_t *graph,+                                       igraph_matrix_t *res,+                                       igraph_bool_t use_seed,+                                       igraph_integer_t niter,+                                       igraph_real_t start_temp,+                                       igraph_layout_grid_t grid,+                                       const igraph_vector_t *weight,+                                       const igraph_vector_t *minx,+                                       const igraph_vector_t *maxx,+                                       const igraph_vector_t *miny,+                                       const igraph_vector_t *maxy) {++    igraph_integer_t no_nodes = igraph_vcount(graph);++    if (niter < 0) {+        IGRAPH_ERROR("Number of iterations must be non-negative in "+                     "Fruchterman-Reingold layout", IGRAPH_EINVAL);+    }++    if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||+                     igraph_matrix_ncol(res) != 2)) {+        IGRAPH_ERROR("Invalid start position matrix size in "+                     "Fruchterman-Reingold layout", IGRAPH_EINVAL);+    }++    if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {+        IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+    }++    if (minx && igraph_vector_size(minx) != no_nodes) {+        IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);+    }+    if (maxx && igraph_vector_size(maxx) != no_nodes) {+        IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);+    }+    if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {+        IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);+    }+    if (miny && igraph_vector_size(miny) != no_nodes) {+        IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);+    }+    if (maxy && igraph_vector_size(maxy) != no_nodes) {+        IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);+    }+    if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {+        IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);+    }++    if (grid == IGRAPH_LAYOUT_AUTOGRID) {+        if (no_nodes > 1000) {+            grid = IGRAPH_LAYOUT_GRID;+        } else {+            grid = IGRAPH_LAYOUT_NOGRID;+        }+    }++    if (grid == IGRAPH_LAYOUT_GRID) {+        return igraph_layout_i_grid_fr(graph, res, use_seed, niter, start_temp,+                                       weight, minx, maxx, miny, maxy);+    } else {+        return igraph_layout_i_fr(graph, res, use_seed, niter, start_temp,+                                  weight, minx, maxx, miny, maxy);+    }+}++/**+ * \function igraph_layout_fruchterman_reingold_3d+ * \brief 3D Fruchterman-Reingold algorithm.+ *+ * This is the 3D version of the force based+ * Fruchterman-Reingold layout (see \ref+ * igraph_layout_fruchterman_reingold for the 2D version+ *+ * \param graph Pointer to an initialized graph object.+ * \param res Pointer to an initialized matrix object. This will+ *        contain the result and will be resized as needed.+ * \param use_seed Logical, if true the supplied values in the+ *        \p res argument are used as an initial layout, if+ *        false a random initial layout is used.+ * \param niter The number of iterations to do. A reasonable+ *        default value is 500.+ * \param start_temp Start temperature. This is the maximum amount+ *        of movement alloved along one axis, within one step, for a+ *        vertex. Currently it is decreased linearly to zero during+ *        the iteration.+ * \param weight Pointer to a vector containing edge weights,+ *        the attraction along the edges will be multiplied by these.+ *        It will be ignored if it is a null-pointer.+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote x \endquote coordinate for every vertex.+ * \param maxx Same as \p minx, but the maximum \quote x \endquote+ *        coordinates.+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote y \endquote coordinate for every vertex.+ * \param maxy Same as \p miny, but the maximum \quote y \endquote+ *        coordinates.+ * \param minz Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote z \endquote coordinate for every vertex.+ * \param maxz Same as \p minz, but the maximum \quote z \endquote+ *        coordinates.+ * \return Error code.+ *+ * Added in version 0.2.</para><para>+ *+ * Time complexity: O(|V|^2) in each+ * iteration, |V| is the number of+ * vertices in the graph.+ *+ */++int igraph_layout_fruchterman_reingold_3d(const igraph_t *graph,+        igraph_matrix_t *res,+        igraph_bool_t use_seed,+        igraph_integer_t niter,+        igraph_real_t start_temp,+        const igraph_vector_t *weight,+        const igraph_vector_t *minx,+        const igraph_vector_t *maxx,+        const igraph_vector_t *miny,+        const igraph_vector_t *maxy,+        const igraph_vector_t *minz,+        const igraph_vector_t *maxz) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_integer_t no_edges = igraph_ecount(graph);+    igraph_integer_t i;+    igraph_vector_float_t dispx, dispy, dispz;+    igraph_real_t temp = start_temp;+    igraph_real_t difftemp = start_temp / niter;+    float width = sqrtf(no_nodes), height = width, depth = width;+    igraph_bool_t conn = 1;+    float C;++    if (niter < 0) {+        IGRAPH_ERROR("Number of iterations must be non-negative in "+                     "Fruchterman-Reingold layout", IGRAPH_EINVAL);+    }++    if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||+                     igraph_matrix_ncol(res) != 3)) {+        IGRAPH_ERROR("Invalid start position matrix size in "+                     "Fruchterman-Reingold layout", IGRAPH_EINVAL);+    }++    if (weight && igraph_vector_size(weight) != igraph_ecount(graph)) {+        IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+    }++    if (minx && igraph_vector_size(minx) != no_nodes) {+        IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);+    }+    if (maxx && igraph_vector_size(maxx) != no_nodes) {+        IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);+    }+    if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {+        IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);+    }+    if (miny && igraph_vector_size(miny) != no_nodes) {+        IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);+    }+    if (maxy && igraph_vector_size(maxy) != no_nodes) {+        IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);+    }+    if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {+        IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);+    }+    if (minz && igraph_vector_size(minz) != no_nodes) {+        IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL);+    }+    if (maxz && igraph_vector_size(maxz) != no_nodes) {+        IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL);+    }+    if (minz && maxz && !igraph_vector_all_le(minz, maxz)) {+        IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL);+    }++    igraph_is_connected(graph, &conn, IGRAPH_WEAK);+    if (!conn) {+        C = no_nodes * sqrtf(no_nodes);+    }++    RNG_BEGIN();++    if (!use_seed) {+        IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3));+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t x1 = minx ? VECTOR(*minx)[i] : -width / 2;+            igraph_real_t x2 = maxx ? VECTOR(*maxx)[i] :  width / 2;+            igraph_real_t y1 = miny ? VECTOR(*miny)[i] : -height / 2;+            igraph_real_t y2 = maxy ? VECTOR(*maxy)[i] :  height / 2;+            igraph_real_t z1 = minz ? VECTOR(*minz)[i] : -depth / 2;+            igraph_real_t z2 = maxz ? VECTOR(*maxz)[i] :  depth / 2;+            MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);+            MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);+            MATRIX(*res, i, 2) = RNG_UNIF(z1, z2);+        }+    }++    IGRAPH_CHECK(igraph_vector_float_init(&dispx, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &dispx);+    IGRAPH_CHECK(igraph_vector_float_init(&dispy, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &dispy);+    IGRAPH_CHECK(igraph_vector_float_init(&dispz, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &dispz);++    for (i = 0; i < niter; i++) {+        igraph_integer_t v, u, e;++        /* calculate repulsive forces, we have a special version+           for unconnected graphs */+        igraph_vector_float_null(&dispx);+        igraph_vector_float_null(&dispy);+        igraph_vector_float_null(&dispz);+        if (conn) {+            for (v = 0; v < no_nodes; v++) {+                for (u = v + 1; u < no_nodes; u++) {+                    float dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+                    float dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+                    float dz = MATRIX(*res, v, 2) - MATRIX(*res, u, 2);+                    float dlen = dx * dx + dy * dy + dz * dz;++                    if (dlen == 0) {+                        dx = RNG_UNIF01() * 1e-9;+                        dy = RNG_UNIF01() * 1e-9;+                        dz = RNG_UNIF01() * 1e-9;+                        dlen = dx * dx + dy * dy + dz * dz;+                    }++                    VECTOR(dispx)[v] += dx / dlen;+                    VECTOR(dispy)[v] += dy / dlen;+                    VECTOR(dispz)[v] += dz / dlen;+                    VECTOR(dispx)[u] -= dx / dlen;+                    VECTOR(dispy)[u] -= dy / dlen;+                    VECTOR(dispz)[u] -= dz / dlen;+                }+            }+        } else {+            for (v = 0; v < no_nodes; v++) {+                for (u = v + 1; u < no_nodes; u++) {+                    float dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+                    float dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+                    float dz = MATRIX(*res, v, 2) - MATRIX(*res, u, 2);+                    float dlen, rdlen;++                    dlen = dx * dx + dy * dy + dz * dz;+                    if (dlen == 0) {+                        dx = RNG_UNIF01() * 1e-9;+                        dy = RNG_UNIF01() * 1e-9;+                        dz = RNG_UNIF01() * 1e-9;+                        dlen = dx * dx + dy * dy + dz * dz;+                    }++                    rdlen = sqrt(dlen);++                    VECTOR(dispx)[v] += dx * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispy)[v] += dy * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispy)[v] += dz * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispx)[u] -= dx * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispy)[u] -= dy * (C - dlen * rdlen) / (dlen * C);+                    VECTOR(dispz)[u] -= dz * (C - dlen * rdlen) / (dlen * C);+                }+            }+        }++        /* calculate attractive forces */+        for (e = 0; e < no_edges; e++) {+            /* each edges is an ordered pair of vertices v and u */+            igraph_integer_t v = IGRAPH_FROM(graph, e);+            igraph_integer_t u = IGRAPH_TO(graph, e);+            igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+            igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+            igraph_real_t dz = MATRIX(*res, v, 2) - MATRIX(*res, u, 2);+            igraph_real_t w = weight ? VECTOR(*weight)[e] : 1.0;+            igraph_real_t dlen = sqrt(dx * dx + dy * dy + dz * dz) * w;+            VECTOR(dispx)[v] -= (dx * dlen);+            VECTOR(dispy)[v] -= (dy * dlen);+            VECTOR(dispz)[v] -= (dz * dlen);+            VECTOR(dispx)[u] += (dx * dlen);+            VECTOR(dispy)[u] += (dy * dlen);+            VECTOR(dispz)[u] += (dz * dlen);+        }++        /* limit max displacement to temperature t and prevent from+           displacement outside frame */+        for (v = 0; v < no_nodes; v++) {+            igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF01() * 1e-9;+            igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF01() * 1e-9;+            igraph_real_t dz = VECTOR(dispz)[v] + RNG_UNIF01() * 1e-9;+            igraph_real_t displen = sqrt(dx * dx + dy * dy + dz * dz);+            igraph_real_t mx = fabs(dx) < temp ? dx : temp;+            igraph_real_t my = fabs(dy) < temp ? dy : temp;+            igraph_real_t mz = fabs(dz) < temp ? dz : temp;+            if (displen > 0) {+                MATRIX(*res, v, 0) += (dx / displen) * mx;+                MATRIX(*res, v, 1) += (dy / displen) * my;+                MATRIX(*res, v, 2) += (dz / displen) * mz;+            }+            if (minx && MATRIX(*res, v, 0) < VECTOR(*minx)[v]) {+                MATRIX(*res, v, 0) = VECTOR(*minx)[v];+            }+            if (maxx && MATRIX(*res, v, 0) > VECTOR(*maxx)[v]) {+                MATRIX(*res, v, 0) = VECTOR(*maxx)[v];+            }+            if (miny && MATRIX(*res, v, 1) < VECTOR(*miny)[v]) {+                MATRIX(*res, v, 1) = VECTOR(*miny)[v];+            }+            if (maxy && MATRIX(*res, v, 1) > VECTOR(*maxy)[v]) {+                MATRIX(*res, v, 1) = VECTOR(*maxy)[v];+            }+            if (minz && MATRIX(*res, v, 2) < VECTOR(*minz)[v]) {+                MATRIX(*res, v, 2) = VECTOR(*minz)[v];+            }+            if (maxz && MATRIX(*res, v, 2) > VECTOR(*maxz)[v]) {+                MATRIX(*res, v, 2) = VECTOR(*maxz)[v];+            }+        }++        temp -= difftemp;+    }++    RNG_END();++    igraph_vector_float_destroy(&dispx);+    igraph_vector_float_destroy(&dispy);+    igraph_vector_float_destroy(&dispz);+    IGRAPH_FINALLY_CLEAN(3);++    return 0;+}
+ igraph/src/layout_gem.c view
@@ -0,0 +1,246 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R package.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_layout.h"+#include "igraph_interface.h"+#include "igraph_random.h"+#include "igraph_math.h"++/**+ * \ingroup layout+ * \function igraph_layout_gem+ *+ * The GEM layout algorithm, as described in Arne Frick, Andreas Ludwig,+ * Heiko Mehldau: A Fast Adaptive Layout Algorithm for Undirected Graphs,+ * Proc. Graph Drawing 1994, LNCS 894, pp. 388-403, 1995.+ * \param graph The input graph. Edge directions are ignored in+ *        directed graphs.+ * \param res The result is stored here. If the \p use_seed argument+ *        is true (non-zero), then this matrix is also used as the+ *        starting point of the algorithm.+ * \param use_seed Boolean, whether to use the supplied coordinates in+ *        \p res as the starting point. If false (zero), then a+ *        uniform random starting point is used.+ * \param maxiter The maximum number of iterations to+ *        perform. Updating a single vertex counts as an iteration.+ *        A reasonable default is 40 * n * n, where n is the number of+ *        vertices. The original paper suggests 4 * n * n, but this+ *        usually only works if the other parameters are set up carefully.+ * \param temp_max The maximum allowed local temperature. A reasonable+ *        default is the number of vertices.+ * \param temp_min The global temperature at which the algorithm+ *        terminates (even before reaching \p maxiter iterations). A+ *        reasonable default is 1/10.+ * \param temp_init Initial local temperature of all vertices. A+ *        reasonable default is the square root of the number of+ *        vertices.+ * \return Error code.+ *+ * Time complexity: O(t * n * (n+e)), where n is the number of vertices,+ * e is the number of edges and t is the number of time steps+ * performed.+ */++int igraph_layout_gem(const igraph_t *graph, igraph_matrix_t *res,+                      igraph_bool_t use_seed, igraph_integer_t maxiter,+                      igraph_real_t temp_max, igraph_real_t temp_min,+                      igraph_real_t temp_init) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_vector_int_t perm;+    igraph_vector_float_t impulse_x, impulse_y, temp, skew_gauge;+    igraph_integer_t i;+    float temp_global;+    igraph_integer_t perm_pointer = 0;+    float barycenter_x = 0.0, barycenter_y = 0.0;+    igraph_vector_t phi;+    igraph_vector_t neis;+    const float elen_des2 = 128 * 128;+    const float gamma = 1 / 16.0;+    const float alpha_o = M_PI;+    const float alpha_r = M_PI / 3.0;+    const float sigma_o = 1.0 / 3.0;+    const float sigma_r = 1.0 / 2.0 / no_nodes;++    if (maxiter < 0) {+        IGRAPH_ERROR("Number of iterations must be non-negative in GEM layout",+                     IGRAPH_EINVAL);+    }+    if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||+                     igraph_matrix_ncol(res) != 2)) {+        IGRAPH_ERROR("Invalid start position matrix size in GEM layout",+                     IGRAPH_EINVAL);+    }+    if (temp_max <= 0) {+        IGRAPH_ERROR("Maximum temperature should be positive in GEM layout",+                     IGRAPH_EINVAL);+    }+    if (temp_min <= 0) {+        IGRAPH_ERROR("Minimum temperature should be positive in GEM layout",+                     IGRAPH_EINVAL);+    }+    if (temp_init <= 0) {+        IGRAPH_ERROR("Initial temperature should be positive in GEM layout",+                     IGRAPH_EINVAL);+    }+    if (temp_max < temp_init || temp_init < temp_min) {+        IGRAPH_ERROR("Minimum <= Initial <= Maximum temperature is required "+                     "in GEM layout", IGRAPH_EINVAL);+    }++    if (no_nodes == 0) {+        return 0;+    }++    IGRAPH_CHECK(igraph_vector_float_init(&impulse_x, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &impulse_x);+    IGRAPH_CHECK(igraph_vector_float_init(&impulse_y, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &impulse_y);+    IGRAPH_CHECK(igraph_vector_float_init(&temp, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &temp);+    IGRAPH_CHECK(igraph_vector_float_init(&skew_gauge, no_nodes));+    IGRAPH_FINALLY(igraph_vector_float_destroy, &skew_gauge);+    IGRAPH_CHECK(igraph_vector_int_init_seq(&perm, 0, no_nodes - 1));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &perm);+    IGRAPH_VECTOR_INIT_FINALLY(&phi, no_nodes);+    IGRAPH_VECTOR_INIT_FINALLY(&neis, 10);++    RNG_BEGIN();++    /* Initialization */+    igraph_degree(graph, &phi, igraph_vss_all(), IGRAPH_ALL, IGRAPH_LOOPS);+    if (!use_seed) {+        const igraph_real_t width_half = no_nodes * 100, height_half = width_half;+        IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));+        for (i = 0; i < no_nodes; i++) {+            MATRIX(*res, i, 0) = RNG_UNIF(-width_half, width_half);+            MATRIX(*res, i, 1) = RNG_UNIF(-height_half, height_half);+            barycenter_x += MATRIX(*res, i, 0);+            barycenter_y += MATRIX(*res, i, 1);+            VECTOR(phi)[i] *= (VECTOR(phi)[i] / 2.0 + 1.0);+        }+    } else {+        for (i = 0; i < no_nodes; i++) {+            barycenter_x += MATRIX(*res, i, 0);+            barycenter_y += MATRIX(*res, i, 1);+            VECTOR(phi)[i] *= (VECTOR(phi)[i] / 2.0 + 1.0);+        }+    }+    igraph_vector_float_fill(&temp, temp_init);+    temp_global = temp_init * no_nodes;++    while (temp_global > temp_min * no_nodes && maxiter > 0) {++        /* choose a vertex v to update */+        igraph_integer_t u, v, nlen, j;+        float px, py, pvx, pvy;+        if (!perm_pointer) {+            igraph_vector_int_shuffle(&perm);+            perm_pointer = no_nodes - 1;+        }+        v = VECTOR(perm)[perm_pointer--];++        /* compute v's impulse */+        px = (barycenter_x / no_nodes - MATRIX(*res, v, 0)) * gamma * VECTOR(phi)[v];+        py = (barycenter_y / no_nodes - MATRIX(*res, v, 1)) * gamma * VECTOR(phi)[v];+        px += RNG_UNIF(-32.0, 32.0);+        py += RNG_UNIF(-32.0, 32.0);++        for (u = 0; u < no_nodes; u++) {+            float dx, dy, dist2;+            if (u == v) {+                continue;+            }+            dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+            dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+            dist2 = dx * dx + dy * dy;+            if (dist2 != 0) {+                px += dx * elen_des2 / dist2;+                py += dy * elen_des2 / dist2;+            }+        }++        IGRAPH_CHECK(igraph_neighbors(graph, &neis, v, IGRAPH_ALL));+        nlen = igraph_vector_size(&neis);+        for (j = 0; j < nlen; j++) {+            igraph_integer_t u = VECTOR(neis)[j];+            float dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0);+            float dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1);+            float dist2 = dx * dx + dy * dy;+            px -= dx * dist2 / (elen_des2 * VECTOR(phi)[v]);+            py -= dy * dist2 / (elen_des2 * VECTOR(phi)[v]);+        }++        /* update v's position and temperature */+        if (px != 0 || py != 0) {+            float plen = sqrtf(px * px + py * py);+            px *= VECTOR(temp)[v] / plen;+            py *= VECTOR(temp)[v] / plen;+            MATRIX(*res, v, 0) += px;+            MATRIX(*res, v, 1) += py;+            barycenter_x += px;+            barycenter_y += py;+        }++        pvx = VECTOR(impulse_x)[v]; pvy = VECTOR(impulse_y)[v];+        if (pvx != 0 || pvy != 0) {+            float beta = atan2f(pvy - py, pvx - px);+            float sin_beta = sinf(beta);+            float sign_sin_beta = (sin_beta > 0) ? 1 : ((sin_beta < 0) ? -1 : 0);+            float cos_beta = cosf(beta);+            float abs_cos_beta = fabsf(cos_beta);+            float old_temp = VECTOR(temp)[v];+            if (sin(beta) >= sin(M_PI_2 + alpha_r / 2.0)) {+                VECTOR(skew_gauge)[v] += sigma_r * sign_sin_beta;+            }+            if (abs_cos_beta >= cosf(alpha_o / 2.0)) {+                VECTOR(temp)[v] *= sigma_o * cos_beta;+            }+            VECTOR(temp)[v] *= (1 - fabsf(VECTOR(skew_gauge)[v]));+            if (VECTOR(temp)[v] > temp_max) {+                VECTOR(temp)[v] = temp_max;+            }+            VECTOR(impulse_x)[v] = px;+            VECTOR(impulse_y)[v] = py;+            temp_global += VECTOR(temp)[v] - old_temp;+        }++        maxiter--;++    } /* while temp && iter */+++    RNG_END();++    igraph_vector_destroy(&neis);+    igraph_vector_destroy(&phi);+    igraph_vector_int_destroy(&perm);+    igraph_vector_float_destroy(&skew_gauge);+    igraph_vector_float_destroy(&temp);+    igraph_vector_float_destroy(&impulse_y);+    igraph_vector_float_destroy(&impulse_x);+    IGRAPH_FINALLY_CLEAN(7);++    return 0;+}
+ igraph/src/layout_kk.c view
@@ -0,0 +1,680 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R package.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_layout.h"+#include "igraph_interface.h"+#include "igraph_paths.h"+#include "igraph_random.h"++/**+ * \ingroup layout+ * \function igraph_layout_kamada_kawai+ * \brief Places the vertices on a plane according the Kamada-Kawai algorithm.+ *+ * </para><para>+ * This is a force directed layout, see  Kamada, T. and Kawai, S.: An+ * Algorithm for Drawing General Undirected Graphs. Information+ * Processing Letters, 31/1, 7--15, 1989.+ * \param graph A graph object.+ * \param res Pointer to an initialized matrix object. This will+ *        contain the result (x-positions in column zero and+ *        y-positions in column one) and will be resized if needed.+ * \param use_seed Boolean, whether to use the values supplied in the+ *        \p res argument as the initial configuration. If zero then a+ *        random initial configuration is used.+ * \param maxiter The maximum number of iterations to perform. A reasonable+ *        default value is at least ten (or more) times the number of+ *        vertices.+ * \param epsilon Stop the iteration, if the maximum delta value of the+ *        algorithm is smaller than still. It is safe to leave it at zero,+ *        and then \p maxiter iterations are performed.+ * \param kkconst The Kamada-Kawai vertex attraction constant.+ *        Typical value: number of vertices.+ * \param weights Edge weights, larger values will result longer edges.+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote x \endquote coordinate for every vertex.+ * \param maxx Same as \p minx, but the maximum \quote x \endquote+ *        coordinates.+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote y \endquote coordinate for every vertex.+ * \param maxy Same as \p miny, but the maximum \quote y \endquote+ *        coordinates.+ * \return Error code.+ *+ * Time complexity: O(|V|) for each iteration, after an O(|V|^2+ * log|V|) initialization step. |V| is the number of vertices in the+ * graph.+ */++int igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t *res,+                               igraph_bool_t use_seed, igraph_integer_t maxiter,+                               igraph_real_t epsilon, igraph_real_t kkconst,+                               const igraph_vector_t *weights,+                               const igraph_vector_t *minx, const igraph_vector_t *maxx,+                               const igraph_vector_t *miny, const igraph_vector_t *maxy) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_integer_t no_edges = igraph_ecount(graph);+    igraph_real_t L, L0 = sqrt(no_nodes);+    igraph_matrix_t dij, lij, kij;+    igraph_real_t max_dij;+    igraph_vector_t D1, D2;+    igraph_integer_t i, j, m;++    if (maxiter < 0) {+        IGRAPH_ERROR("Number of iterations must be non-negatice in "+                     "Kamada-Kawai layout", IGRAPH_EINVAL);+    }+    if (kkconst <= 0) {+        IGRAPH_ERROR("`K' constant must be positive in Kamada-Kawai layout",+                     IGRAPH_EINVAL);+    }++    if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||+                     igraph_matrix_ncol(res) != 2)) {+        IGRAPH_ERROR("Invalid start position matrix size in "+                     "Kamada-Kawai layout", IGRAPH_EINVAL);+    }+    if (weights && igraph_vector_size(weights) != no_edges) {+        IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+    }++    if (minx && igraph_vector_size(minx) != no_nodes) {+        IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);+    }+    if (maxx && igraph_vector_size(maxx) != no_nodes) {+        IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);+    }+    if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {+        IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);+    }+    if (miny && igraph_vector_size(miny) != no_nodes) {+        IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);+    }+    if (maxy && igraph_vector_size(maxy) != no_nodes) {+        IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);+    }+    if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {+        IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);+    }++    if (!use_seed) {+        if (minx || maxx || miny || maxy) {+            const igraph_real_t width = sqrt(no_nodes), height = width;+            IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 2));+            RNG_BEGIN();+            for (i = 0; i < no_nodes; i++) {+                igraph_real_t x1 = minx ? VECTOR(*minx)[i] : -width / 2;+                igraph_real_t x2 = maxx ? VECTOR(*maxx)[i] :  width / 2;+                igraph_real_t y1 = miny ? VECTOR(*miny)[i] : -height / 2;+                igraph_real_t y2 = maxy ? VECTOR(*maxy)[i] :  height / 2;+                if (!igraph_finite(x1)) {+                    x1 = -width / 2;+                }+                if (!igraph_finite(x2)) {+                    x2 =  width / 2;+                }+                if (!igraph_finite(y1)) {+                    y1 = -height / 2;+                }+                if (!igraph_finite(y2)) {+                    y2 =  height / 2;+                }+                MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);+                MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);+            }+            RNG_END();+        } else {+            igraph_layout_circle(graph, res, /* order= */ igraph_vss_all());+        }+    }++    if (no_nodes <= 1) {+        return 0;+    }++    IGRAPH_MATRIX_INIT_FINALLY(&dij, no_nodes, no_nodes);+    IGRAPH_MATRIX_INIT_FINALLY(&kij, no_nodes, no_nodes);+    IGRAPH_MATRIX_INIT_FINALLY(&lij, no_nodes, no_nodes);++    if (weights && igraph_vector_min(weights) < 0) {+        IGRAPH_CHECK(igraph_shortest_paths_bellman_ford(graph, &dij, igraph_vss_all(),+                     igraph_vss_all(), weights,+                     IGRAPH_ALL));+    } else {++        IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, &dij, igraph_vss_all(),+                     igraph_vss_all(), weights,+                     IGRAPH_ALL));+    }++    max_dij = 0.0;+    for (i = 0; i < no_nodes; i++) {+        for (j = i + 1; j < no_nodes; j++) {+            if (!igraph_finite(MATRIX(dij, i, j))) {+                continue;+            }+            if (MATRIX(dij, i, j) > max_dij) {+                max_dij = MATRIX(dij, i, j);+            }+        }+    }+    for (i = 0; i < no_nodes; i++) {+        for (j = 0; j < no_nodes; j++) {+            if (MATRIX(dij, i, j) > max_dij) {+                MATRIX(dij, i, j) = max_dij;+            }+        }+    }++    L = L0 / max_dij;+    for (i = 0; i < no_nodes; i++) {+        for (j = 0; j < no_nodes; j++) {+            igraph_real_t tmp = MATRIX(dij, i, j) * MATRIX(dij, i, j);+            if (i == j) {+                continue;+            }+            MATRIX(kij, i, j) = kkconst / tmp;+            MATRIX(lij, i, j) = L * MATRIX(dij, i, j);+        }+    }++    /* Initialize delta */+    IGRAPH_VECTOR_INIT_FINALLY(&D1, no_nodes);+    IGRAPH_VECTOR_INIT_FINALLY(&D2, no_nodes);+    for (m = 0; m < no_nodes; m++) {+        igraph_real_t myD1 = 0.0, myD2 = 0.0;+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t dx, dy, mi_dist;+            if (i == m) {+                continue;+            }+            dx = MATRIX(*res, m, 0) - MATRIX(*res, i, 0);+            dy = MATRIX(*res, m, 1) - MATRIX(*res, i, 1);+            mi_dist = sqrt(dx * dx + dy * dy);+            myD1 += MATRIX(kij, m, i) * (dx - MATRIX(lij, m, i) * dx / mi_dist);+            myD2 += MATRIX(kij, m, i) * (dy - MATRIX(lij, m, i) * dy / mi_dist);+        }+        VECTOR(D1)[m] = myD1;+        VECTOR(D2)[m] = myD2;+    }++    for (j = 0; j < maxiter; j++) {+        igraph_real_t myD1, myD2, A, B, C;+        igraph_real_t max_delta, delta_x, delta_y;+        igraph_real_t old_x, old_y, new_x, new_y;++        myD1 = 0.0, myD2 = 0.0, A = 0.0, B = 0.0, C = 0.0;++        /* Select maximal delta */+        m = 0; max_delta = -1;+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t delta = (VECTOR(D1)[i] * VECTOR(D1)[i] ++                                   VECTOR(D2)[i] * VECTOR(D2)[i]);+            if (delta > max_delta) {+                m = i; max_delta = delta;+            }+        }+        if (max_delta < epsilon) {+            break;+        }+        old_x = MATRIX(*res, m, 0);+        old_y = MATRIX(*res, m, 1);++        /* Calculate D1 and D2, A, B, C */+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t dx, dy, dist, den;+            if (i == m) {+                continue;+            }+            dx = old_x - MATRIX(*res, i, 0);+            dy = old_y - MATRIX(*res, i, 1);+            dist = sqrt(dx * dx + dy * dy);+            den = dist * (dx * dx + dy * dy);+            A += MATRIX(kij, m, i) * (1 - MATRIX(lij, m, i) * dy * dy / den);+            B += MATRIX(kij, m, i) * MATRIX(lij, m, i) * dx * dy / den;+            C += MATRIX(kij, m, i) * (1 - MATRIX(lij, m, i) * dx * dx / den);+        }+        myD1 = VECTOR(D1)[m];+        myD2 = VECTOR(D2)[m];++        /* Need to solve some linear equations */+        delta_y = (B * myD1 - myD2 * A) / (C * A - B * B);+        delta_x = - (myD1 + B * delta_y) / A;++        new_x = old_x + delta_x;+        new_y = old_y + delta_y;++        /* Limits, if given */+        if (minx && new_x < VECTOR(*minx)[m]) {+            new_x = VECTOR(*minx)[m];+        }+        if (maxx && new_x > VECTOR(*maxx)[m]) {+            new_x = VECTOR(*maxx)[m];+        }+        if (miny && new_y < VECTOR(*miny)[m]) {+            new_y = VECTOR(*miny)[m];+        }+        if (maxy && new_y > VECTOR(*maxy)[m]) {+            new_y = VECTOR(*maxy)[m];+        }++        /* Update delta, only with/for the affected node */+        VECTOR(D1)[m] = VECTOR(D2)[m] = 0.0;+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t old_dx, old_dy, old_mi, new_dx, new_dy, new_mi_dist, old_mi_dist;+            if (i == m) {+                continue;+            }+            old_dx = old_x - MATRIX(*res, i, 0);+            old_dy = old_y - MATRIX(*res, i, 1);+            old_mi_dist = sqrt(old_dx * old_dx + old_dy * old_dy);+            new_dx = new_x - MATRIX(*res, i, 0);+            new_dy = new_y - MATRIX(*res, i, 1);+            new_mi_dist = sqrt(new_dx * new_dx + new_dy * new_dy);++            VECTOR(D1)[i] -= MATRIX(kij, m, i) *+                             (-old_dx + MATRIX(lij, m, i) * old_dx / old_mi_dist);+            VECTOR(D2)[i] -= MATRIX(kij, m, i) *+                             (-old_dy + MATRIX(lij, m, i) * old_dy / old_mi_dist);+            VECTOR(D1)[i] += MATRIX(kij, m, i) *+                             (-new_dx + MATRIX(lij, m, i) * new_dx / new_mi_dist);+            VECTOR(D2)[i] += MATRIX(kij, m, i) *+                             (-new_dy + MATRIX(lij, m, i) * new_dy / new_mi_dist);++            VECTOR(D1)[m] += MATRIX(kij, m, i) *+                             (new_dx - MATRIX(lij, m, i) * new_dx / new_mi_dist);+            VECTOR(D2)[m] += MATRIX(kij, m, i) *+                             (new_dy - MATRIX(lij, m, i) * new_dy / new_mi_dist);+        }++        /* Update coordinates*/+        MATRIX(*res, m, 0) = new_x;+        MATRIX(*res, m, 1) = new_y;+    }++    igraph_vector_destroy(&D2);+    igraph_vector_destroy(&D1);+    igraph_matrix_destroy(&lij);+    igraph_matrix_destroy(&kij);+    igraph_matrix_destroy(&dij);+    IGRAPH_FINALLY_CLEAN(5);++    return 0;+}++/**+ * \ingroup layout+ * \function igraph_layout_kamada_kawai_3d+ * \brief 3D version of the Kamada-Kawai layout generator+ *+ * </para><para>+ * This is a force directed layout, see  Kamada, T. and Kawai, S.: An+ * Algorithm for Drawing General Undirected Graphs. Information+ * Processing Letters, 31/1, 7--15, 1989.+ * \param graph A graph object.+ * \param res Pointer to an initialized matrix object. This will+ *        contain the result (x-positions in column zero and+ *        y-positions in column one) and will be resized if needed.+ * \param use_seed Boolean, whether to use the values supplied in the+ *        \p res argument as the initial configuration. If zero then a+ *        random initial configuration is used.+ * \param maxiter The maximum number of iterations to perform. A reasonable+ *        default value is at least ten (or more) times the number of+ *        vertices.+ * \param epsilon Stop the iteration, if the maximum delta value of the+ *        algorithm is smaller than still. It is safe to leave it at zero,+ *        and then \p maxiter iterations are performed.+ * \param kkconst The Kamada-Kawai vertex attraction constant.+ *        Typical value: number of vertices.+ * \param weights Edge weights, larger values will result longer edges.+ * \param minx Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote x \endquote coordinate for every vertex.+ * \param maxx Same as \p minx, but the maximum \quote x \endquote+ *        coordinates.+ * \param miny Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote y \endquote coordinate for every vertex.+ * \param maxy Same as \p miny, but the maximum \quote y \endquote+ *        coordinates.+ * \param minz Pointer to a vector, or a \c NULL pointer. If not a+ *        \c NULL pointer then the vector gives the minimum+ *        \quote z \endquote coordinate for every vertex.+ * \param maxz Same as \p minz, but the maximum \quote z \endquote+ *        coordinates.+ * \return Error code.+ *+ * Time complexity: O(|V|) for each iteration, after an O(|V|^2+ * log|V|) initialization step. |V| is the number of vertices in the+ * graph.+ */++int igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matrix_t *res,+                                  igraph_bool_t use_seed, igraph_integer_t maxiter,+                                  igraph_real_t epsilon, igraph_real_t kkconst,+                                  const igraph_vector_t *weights,+                                  const igraph_vector_t *minx, const igraph_vector_t *maxx,+                                  const igraph_vector_t *miny, const igraph_vector_t *maxy,+                                  const igraph_vector_t *minz, const igraph_vector_t *maxz) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_integer_t no_edges = igraph_ecount(graph);+    igraph_real_t L, L0 = sqrt(no_nodes);+    igraph_matrix_t dij, lij, kij;+    igraph_real_t max_dij;+    igraph_vector_t D1, D2, D3;+    igraph_integer_t i, j, m;++    if (maxiter < 0) {+        IGRAPH_ERROR("Number of iterations must be non-negatice in "+                     "Kamada-Kawai layout", IGRAPH_EINVAL);+    }+    if (kkconst <= 0) {+        IGRAPH_ERROR("`K' constant must be positive in Kamada-Kawai layout",+                     IGRAPH_EINVAL);+    }++    if (use_seed && (igraph_matrix_nrow(res) != no_nodes ||+                     igraph_matrix_ncol(res) != 3)) {+        IGRAPH_ERROR("Invalid start position matrix size in "+                     "3d Kamada-Kawai layout", IGRAPH_EINVAL);+    }+    if (weights && igraph_vector_size(weights) != no_edges) {+        IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+    }++    if (minx && igraph_vector_size(minx) != no_nodes) {+        IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL);+    }+    if (maxx && igraph_vector_size(maxx) != no_nodes) {+        IGRAPH_ERROR("Invalid maxx vector length", IGRAPH_EINVAL);+    }+    if (minx && maxx && !igraph_vector_all_le(minx, maxx)) {+        IGRAPH_ERROR("minx must not be greater than maxx", IGRAPH_EINVAL);+    }+    if (miny && igraph_vector_size(miny) != no_nodes) {+        IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL);+    }+    if (maxy && igraph_vector_size(maxy) != no_nodes) {+        IGRAPH_ERROR("Invalid maxy vector length", IGRAPH_EINVAL);+    }+    if (miny && maxy && !igraph_vector_all_le(miny, maxy)) {+        IGRAPH_ERROR("miny must not be greater than maxy", IGRAPH_EINVAL);+    }+    if (minz && igraph_vector_size(minz) != no_nodes) {+        IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL);+    }+    if (maxz && igraph_vector_size(maxz) != no_nodes) {+        IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL);+    }+    if (minz && maxz && !igraph_vector_all_le(minz, maxz)) {+        IGRAPH_ERROR("minz must not be greater than maxz", IGRAPH_EINVAL);+    }++    if (!use_seed) {+        if (minx || maxx || miny || maxy || minz || maxz) {+            const igraph_real_t width = sqrt(no_nodes), height = width, depth = width;+            IGRAPH_CHECK(igraph_matrix_resize(res, no_nodes, 3));+            RNG_BEGIN();+            for (i = 0; i < no_nodes; i++) {+                igraph_real_t x1 = minx ? VECTOR(*minx)[i] : -width / 2;+                igraph_real_t x2 = maxx ? VECTOR(*maxx)[i] :  width / 2;+                igraph_real_t y1 = miny ? VECTOR(*miny)[i] : -height / 2;+                igraph_real_t y2 = maxy ? VECTOR(*maxy)[i] :  height / 2;+                igraph_real_t z1 = minz ? VECTOR(*minz)[i] : -depth / 2;+                igraph_real_t z2 = maxz ? VECTOR(*maxz)[i] :  depth / 2;+                if (!igraph_finite(x1)) {+                    x1 = -width / 2;+                }+                if (!igraph_finite(x2)) {+                    x2 =  width / 2;+                }+                if (!igraph_finite(y1)) {+                    y1 = -height / 2;+                }+                if (!igraph_finite(y2)) {+                    y2 =  height / 2;+                }+                if (!igraph_finite(z1)) {+                    z1 = -depth / 2;+                }+                if (!igraph_finite(z2)) {+                    z2 =  depth / 2;+                }+                MATRIX(*res, i, 0) = RNG_UNIF(x1, x2);+                MATRIX(*res, i, 1) = RNG_UNIF(y1, y2);+                MATRIX(*res, i, 2) = RNG_UNIF(z1, z2);+            }+            RNG_END();+        } else {+            igraph_layout_sphere(graph, res);+        }+    }++    if (no_nodes <= 1) {+        return 0;+    }++    IGRAPH_MATRIX_INIT_FINALLY(&dij, no_nodes, no_nodes);+    IGRAPH_MATRIX_INIT_FINALLY(&kij, no_nodes, no_nodes);+    IGRAPH_MATRIX_INIT_FINALLY(&lij, no_nodes, no_nodes);+    IGRAPH_CHECK(igraph_shortest_paths_dijkstra(graph, &dij, igraph_vss_all(),+                 igraph_vss_all(), weights,+                 IGRAPH_ALL));++    max_dij = 0.0;+    for (i = 0; i < no_nodes; i++) {+        for (j = i + 1; j < no_nodes; j++) {+            if (!igraph_finite(MATRIX(dij, i, j))) {+                continue;+            }+            if (MATRIX(dij, i, j) > max_dij) {+                max_dij = MATRIX(dij, i, j);+            }+        }+    }+    for (i = 0; i < no_nodes; i++) {+        for (j = 0; j < no_nodes; j++) {+            if (MATRIX(dij, i, j) > max_dij) {+                MATRIX(dij, i, j) = max_dij;+            }+        }+    }++    L = L0 / max_dij;+    for (i = 0; i < no_nodes; i++) {+        for (j = 0; j < no_nodes; j++) {+            igraph_real_t tmp = MATRIX(dij, i, j) * MATRIX(dij, i, j);+            if (i == j) {+                continue;+            }+            MATRIX(kij, i, j) = kkconst / tmp;+            MATRIX(lij, i, j) = L * MATRIX(dij, i, j);+        }+    }++    /* Initialize delta */+    IGRAPH_VECTOR_INIT_FINALLY(&D1, no_nodes);+    IGRAPH_VECTOR_INIT_FINALLY(&D2, no_nodes);+    IGRAPH_VECTOR_INIT_FINALLY(&D3, no_nodes);+    for (m = 0; m < no_nodes; m++) {+        igraph_real_t dx, dy, dz, mi_dist;+        igraph_real_t myD1 = 0.0, myD2 = 0.0, myD3 = 0.0;+        for (i = 0; i < no_nodes; i++) {+            if (i == m) {+                continue;+            }+            dx = MATRIX(*res, m, 0) - MATRIX(*res, i, 0);+            dy = MATRIX(*res, m, 1) - MATRIX(*res, i, 1);+            dz = MATRIX(*res, m, 2) - MATRIX(*res, i, 2);+            mi_dist = sqrt(dx * dx + dy * dy + dz * dz);+            myD1 += MATRIX(kij, m, i) * (dx - MATRIX(lij, m, i) * dx / mi_dist);+            myD2 += MATRIX(kij, m, i) * (dy - MATRIX(lij, m, i) * dy / mi_dist);+            myD3 += MATRIX(kij, m, i) * (dz - MATRIX(lij, m, i) * dz / mi_dist);+        }+        VECTOR(D1)[m] = myD1;+        VECTOR(D2)[m] = myD2;+        VECTOR(D3)[m] = myD3;+    }++    for (j = 0; j < maxiter; j++) {++        igraph_real_t Ax = 0.0, Ay = 0.0, Az = 0.0;+        igraph_real_t Axx = 0.0, Axy = 0.0, Axz = 0.0, Ayy = 0.0, Ayz = 0.0, Azz = 0.0;+        igraph_real_t max_delta, delta_x, delta_y, delta_z;+        igraph_real_t old_x, old_y, old_z, new_x, new_y, new_z;+        igraph_real_t detnum;++        /* Select maximal delta */+        m = 0; max_delta = -1;+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t delta = (VECTOR(D1)[i] * VECTOR(D1)[i] ++                                   VECTOR(D2)[i] * VECTOR(D2)[i] ++                                   VECTOR(D3)[i] * VECTOR(D3)[i]);+            if (delta > max_delta) {+                m = i; max_delta = delta;+            }+        }+        if (max_delta < epsilon) {+            break;+        }+        old_x = MATRIX(*res, m, 0);+        old_y = MATRIX(*res, m, 1);+        old_z = MATRIX(*res, m, 2);++        /* Calculate D1, D2 and D3, and other coefficients */+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t dx, dy, dz, dist, den, k_mi, l_mi;+            if (i == m) {+                continue;+            }+            dx = old_x - MATRIX(*res, i, 0);+            dy = old_y - MATRIX(*res, i, 1);+            dz = old_z - MATRIX(*res, i, 2);+            dist = sqrt(dx * dx + dy * dy + dz * dz);+            den = dist * (dx * dx + dy * dy + dz * dz);+            k_mi = MATRIX(kij, m, i);+            l_mi = MATRIX(lij, m, i);+            Axx += k_mi * (1 - l_mi * (dy * dy + dz * dz) / den);+            Ayy += k_mi * (1 - l_mi * (dx * dx + dz * dz) / den);+            Azz += k_mi * (1 - l_mi * (dx * dx + dy * dy) / den);+            Axy += k_mi * l_mi * dx * dy / den;+            Axz += k_mi * l_mi * dx * dz / den;+            Ayz += k_mi * l_mi * dy * dz / den;+        }+        Ax = -VECTOR(D1)[m];+        Ay = -VECTOR(D2)[m];+        Az = -VECTOR(D3)[m];++        /* Need to solve some linear equations, we just use Cramer's rule */+#define DET(a,b,c,d,e,f,g,h,i) ((a*e*i+b*f*g+c*d*h)-(c*e*g+b*d*i+a*f*h))++        detnum  = DET(Axx, Axy, Axz, Axy, Ayy, Ayz, Axz, Ayz, Azz);+        delta_x = DET(Ax, Ay, Az, Axy, Ayy, Ayz, Axz, Ayz, Azz) / detnum;+        delta_y = DET(Axx, Axy, Axz, Ax, Ay, Az, Axz, Ayz, Azz) / detnum;+        delta_z = DET(Axx, Axy, Axz, Axy, Ayy, Ayz, Ax, Ay, Az ) / detnum;++        new_x = old_x + delta_x;+        new_y = old_y + delta_y;+        new_z = old_z + delta_z;++        /* Limits, if given */+        if (minx && new_x < VECTOR(*minx)[m]) {+            new_x = VECTOR(*minx)[m];+        }+        if (maxx && new_x > VECTOR(*maxx)[m]) {+            new_x = VECTOR(*maxx)[m];+        }+        if (miny && new_y < VECTOR(*miny)[m]) {+            new_y = VECTOR(*miny)[m];+        }+        if (maxy && new_y > VECTOR(*maxy)[m]) {+            new_y = VECTOR(*maxy)[m];+        }+        if (minz && new_z < VECTOR(*minz)[m]) {+            new_z = VECTOR(*minz)[m];+        }+        if (maxz && new_z > VECTOR(*maxz)[m]) {+            new_z = VECTOR(*maxz)[m];+        }++        /* Update delta, only with/for the affected node */+        VECTOR(D1)[m] = VECTOR(D2)[m] = VECTOR(D3)[m] = 0.0;+        for (i = 0; i < no_nodes; i++) {+            igraph_real_t old_dx, old_dy, old_dz, old_mi_dist, new_dx, new_dy, new_dz, new_mi_dist;+            if (i == m) {+                continue;+            }+            old_dx = old_x - MATRIX(*res, i, 0);+            old_dy = old_y - MATRIX(*res, i, 1);+            old_dz = old_z - MATRIX(*res, i, 2);+            old_mi_dist = sqrt(old_dx * old_dx + old_dy * old_dy ++                               old_dz * old_dz);+            new_dx = new_x - MATRIX(*res, i, 0);+            new_dy = new_y - MATRIX(*res, i, 1);+            new_dz = new_z - MATRIX(*res, i, 2);+            new_mi_dist = sqrt(new_dx * new_dx + new_dy * new_dy ++                               new_dz * new_dz);++            VECTOR(D1)[i] -= MATRIX(kij, m, i) *+                             (-old_dx + MATRIX(lij, m, i) * old_dx / old_mi_dist);+            VECTOR(D2)[i] -= MATRIX(kij, m, i) *+                             (-old_dy + MATRIX(lij, m, i) * old_dy / old_mi_dist);+            VECTOR(D3)[i] -= MATRIX(kij, m, i) *+                             (-old_dz + MATRIX(lij, m, i) * old_dz / old_mi_dist);++            VECTOR(D1)[i] += MATRIX(kij, m, i) *+                             (-new_dx + MATRIX(lij, m, i) * new_dx / new_mi_dist);+            VECTOR(D2)[i] += MATRIX(kij, m, i) *+                             (-new_dy + MATRIX(lij, m, i) * new_dy / new_mi_dist);+            VECTOR(D3)[i] += MATRIX(kij, m, i) *+                             (-new_dz + MATRIX(lij, m, i) * new_dz / new_mi_dist);++            VECTOR(D1)[m] += MATRIX(kij, m, i) *+                             (new_dx - MATRIX(lij, m, i) * new_dx / new_mi_dist);+            VECTOR(D2)[m] += MATRIX(kij, m, i) *+                             (new_dy - MATRIX(lij, m, i) * new_dy / new_mi_dist);+            VECTOR(D3)[m] += MATRIX(kij, m, i) *+                             (new_dz - MATRIX(lij, m, i) * new_dz / new_mi_dist);+        }++        /* Update coordinates*/+        MATRIX(*res, m, 0) = new_x;+        MATRIX(*res, m, 1) = new_y;+        MATRIX(*res, m, 2) = new_z;+    }++    igraph_vector_destroy(&D3);+    igraph_vector_destroy(&D2);+    igraph_vector_destroy(&D1);+    igraph_matrix_destroy(&lij);+    igraph_matrix_destroy(&kij);+    igraph_matrix_destroy(&dij);+    IGRAPH_FINALLY_CLEAN(6);++    return 0;+}
+ igraph/src/lbfgs.c view
@@ -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;+        }+    }+}
+ igraph/src/lbitbits.c view
@@ -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
+ igraph/src/lbitshft.c view
@@ -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
+ igraph/src/len_trim.c view
@@ -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__ */+
+ igraph/src/lread.c view
@@ -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
+ igraph/src/lsame.c view
@@ -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_ */+
+ igraph/src/lsap.c view
@@ -0,0 +1,632 @@++#include "igraph_lsap.h"+#include "igraph_error.h"++#include <stdio.h>+#include <stdlib.h>+#include <math.h>+#include <limits.h>     /* INT_MAX */+#include <float.h>      /* DBL_MAX */+#include <assert.h>+#include <time.h>++/* constants used for improving readability of code */++#define COVERED       1+#define UNCOVERED     0+#define ASSIGNED      1+#define UNASSIGNED    0+#define TRUE          1+#define FALSE         0++#define MARKED        1+#define UNMARKED      0++#define REDUCE        1+#define NOREDUCE      0++typedef struct {+    int        n;            /* order of problem             */+    double   **C;            /* cost matrix          */+    double   **c;            /* reduced cost matrix      */+    int       *s;            /* assignment                   */+    int       *f;            /* column i is assigned to f[i] */+    int       na;            /* number of assigned items;    */+    int     runs;            /* number of iterations     */+    double  cost;            /* minimum cost         */+    time_t rtime;            /* time                         */+} AP;++/* public interface */++/* constructors and destructor */+AP     *ap_create_problem(double *t, int n);+AP     *ap_create_problem_from_matrix(double **t, int n);+AP     *ap_read_problem(char *file);+void    ap_free(AP *p);++int     ap_assignment(AP *p, int *res);+int     ap_costmatrix(AP *p, double **m);+int     ap_datamatrix(AP *p, double **m);+int     ap_iterations(AP *p);+int     ap_hungarian(AP *p);+double  ap_mincost(AP *p);+void    ap_print_solution(AP *p);+void    ap_show_data(AP *p);+int     ap_size(AP *p);+int     ap_time(AP *p);++/* error reporting */+void ap_error(char *message);++/* private functions */+void    preprocess(AP *p);+void    preassign(AP *p);+int     cover(AP *p, int *ri, int *ci);+void    reduce(AP *p, int *ri, int *ci);++int ap_hungarian(AP *p) {+    int      n;            /* size of problem */+    int    *ri;            /* covered rows    */+    int    *ci;            /* covered columns */+    time_t start, end;     /* timer           */+    int i, j, ok;++    start = time(0);++    n = p->n;+    p->runs = 0;++    /* allocate memory */+    p->s = calloc(1 + n, sizeof(int));+    p->f = calloc(1 + n, sizeof(int));++    ri = calloc(1 + n, sizeof(int));+    ci = calloc(1 + n, sizeof(int));++    if (ri == NULL || ci == NULL || p->s == NULL || p->f == NULL) {+        IGRAPH_ERROR("ap_hungarian: could not allocate memory", IGRAPH_ENOMEM);+    }++    preprocess(p);+    preassign(p);++    while (p->na < n) {+        if (REDUCE == cover(p, ri, ci)) {+            reduce(p, ri, ci);+        }+        ++p->runs;+    }++    end = time(0);++    p->rtime = end - start;++    /* check if assignment is a permutation of (1..n) */+    for (i = 1; i <= n; i++) {+        ok = 0;+        for (j = 1; j <= n; j++)+            if (p->s[j] == i) {+                ++ok;+            }+        if (ok != 1)+            IGRAPH_ERROR("ap_hungarian: error in assigment, is not a permutation",+                         IGRAPH_EINVAL);+    }++    /* calculate cost of assignment */+    p->cost = 0;+    for (i = 1; i <= n; i++) {+        p->cost += p->C[i][p->s[i]];+    }++    /* reset result back to base-0 indexing */+    for (i = 1; i <= n; i++) {+        p->s[i - 1] = p->s[i] - 1;+    }++    /* free memory */++    free(ri);+    free(ci);++    return 0;+}++/* abbreviated interface */+int ap_assignment(AP *p, int *res) {+    int i;++    if (p->s == NULL) {+        ap_hungarian(p);+    }++    for (i = 0; i < p->n; i++) {+        res[i] = p->s[i];+    }++    return p->n;+}+++/*******************************************************************/+/* constructors                                                    */+/* read data from file                                             */+/*******************************************************************/++AP *ap_read_problem(char *file) {+    FILE *f;+    int i, j, c;+    int m, n;+    double x;+    double **t;+    int nrow, ncol;+    AP *p;++    f = fopen(file, "r");+    if (f == NULL) {+        return NULL;+    }++    t = (double **)malloc(sizeof(double*));++    m = 0;+    n = 0;++    nrow = 0;+    ncol = 0;++    while (EOF != (i = fscanf(f, "%lf", &x))) {+        if (i == 1) {+            if (n == 0) {+                t = (double **) realloc(t, (m + 1) * sizeof(double *));+                t[m] = (double *) malloc(sizeof(double));+            } else {+                t[m] = (double *) realloc(t[m], (n + 1) * sizeof(double));+            }++            t[m][n++] = x;++            ncol = (ncol < n) ? n : ncol;+            c = fgetc(f);+            if (c == '\n') {+                n = 0;+                ++m;+                nrow = (nrow < m) ? m : nrow;+            }+        }+    }+    fclose(f);++    /* prepare data */++    if (nrow != ncol) {+        /*+          fprintf(stderr,"ap_read_problem: problem not quadratic\nrows =%d, cols = %d\n",nrow,ncol);+        */+        igraph_warningf("ap_read_problem: problem not quadratic\nrows = %d, cols = %d\n",+                        __FILE__, __LINE__, -1, nrow, ncol);+        return NULL;+    }++    p = (AP*) malloc(sizeof(AP));+    p->n = ncol;++    p->C  = (double **) malloc((1 + nrow) * sizeof(double *));+    p->c  = (double **) malloc((1 + nrow) * sizeof(double *));+    if (p->C == NULL || p->c == NULL) {+        return NULL;+    }++    for (i = 1; i <= nrow; i++) {+        p->C[i] = (double *) calloc(ncol + 1, sizeof(double));+        p->c[i] = (double *) calloc(ncol + 1, sizeof(double));+        if (p->C[i] == NULL || p->c[i] == NULL) {+            return NULL;+        }+    }++    for (i = 1; i <= nrow; i++)+        for ( j = 1; j <= ncol; j++) {+            p->C[i][j] = t[i - 1][j - 1];+            p->c[i][j] = t[i - 1][j - 1];+        }++    for (i = 0; i < nrow; i++) {+        free(t[i]);+    }+    free(t);++    p->cost = 0;+    p->s = NULL;+    p->f = NULL;+    return p;+}++AP     *ap_create_problem_from_matrix(double **t, int n) {+    int i, j;+    AP *p;++    p = (AP*) malloc(sizeof(AP));+    if (p == NULL) {+        return NULL;+    }++    p->n = n;++    p->C  = (double **) malloc((n + 1) * sizeof(double *));+    p->c  = (double **) malloc((n + 1) * sizeof(double *));+    if (p->C == NULL || p->c == NULL) {+        return NULL;+    }++    for (i = 1; i <= n; i++) {+        p->C[i] = (double *) calloc(n + 1, sizeof(double));+        p->c[i] = (double *) calloc(n + 1, sizeof(double));+        if (p->C[i] == NULL || p->c[i] == NULL) {+            return NULL;+        }+    }+++    for (i = 1; i <= n; i++)+        for ( j = 1; j <= n; j++) {+            p->C[i][j] = t[i - 1][j - 1];+            p->c[i][j] = t[i - 1][j - 1];+        }+    p->cost = 0;+    p->s = NULL;+    p->f = NULL;+    return p;+}++/* read data from vector */+AP *ap_create_problem(double *t, int n) {+    int i, j;+    AP *p;++    p = (AP*) malloc(sizeof(AP));+    if (p == NULL) {+        return NULL;+    }++    p->n = n;++    p->C  = (double **) malloc((n + 1) * sizeof(double *));+    p->c  = (double **) malloc((n + 1) * sizeof(double *));+    if (p->C == NULL || p->c == NULL) {+        return NULL;+    }++    for (i = 1; i <= n; i++) {+        p->C[i] = (double *) calloc(n + 1, sizeof(double));+        p->c[i] = (double *) calloc(n + 1, sizeof(double));+        if (p->C[i] == NULL || p->c[i] == NULL) {+            return NULL;+        }+    }+++    for (i = 1; i <= n; i++)+        for ( j = 1; j <= n; j++) {+            p->C[i][j] = t[n * (j - 1) + i - 1];+            p->c[i][j] = t[n * (j - 1) + i - 1];+        }+    p->cost = 0;+    p->s = NULL;+    p->f = NULL;+    return p;+}++/* destructor */+void ap_free(AP *p) {+    int i;++    free(p->s);+    free(p->f);++    for (i = 1; i <= p->n; i++) {+        free(p->C[i]);+        free(p->c[i]);+    }++    free(p->C);+    free(p->c);+    free(p);+}++/* set + get functions */++/*+void ap_show_data(AP *p)+{+    int i, j;++    for(i = 1; i <= p->n; i++){+    for(j = 1; j <= p->n; j++)+        printf("%6.2f ", p->c[i][j]);+    printf("\n");+    }+}+*/++double ap_mincost(AP *p) {+    if (p->s == NULL) {+        ap_hungarian(p);+    }++    return p->cost;+}++int ap_size(AP *p) {+    return p->n;+}++int ap_time(AP *p) {+    return (int) p->rtime;+}++int ap_iterations(AP *p) {+    return p->runs;+}++/*+void ap_print_solution(AP *p)+{+    int i;++    printf("%d itertations, %d secs.\n",p->runs, (int)p->rtime);+    printf("Min Cost: %10.4f\n",p->cost);++    for(i = 0; i < p->n; i++)+    printf("%4d",p->s[i]);+    printf("\n");+}+*/++int ap_costmatrix(AP *p, double **m) {+    int i, j;++    for (i = 0; i < p->n; i++)+        for (j = 0; j < p->n; j++) {+            m[i][j] = p->C[i + 1][j + 1];+        }++    return p->n;+}++int ap_datamatrix(AP *p, double **m) {+    int i, j;++    for (i = 0; i < p->n; i++)+        for (j = 0; j < p->n; j++) {+            m[i][j] = p->c[i + 1][j + 1];+        }++    return p->n;+}++/* error reporting */++/*+void ap_error(char *message)+{+    fprintf(stderr,"%s\n",message);+    exit(1);+}+*/++/*************************************************************/+/* these functions are used internally                       */+/* by ap_hungarian                                           */+/*************************************************************/++int cover(AP *p, int *ri, int *ci) {+    int *mr, i, r;+    int n;++    n = p->n;+    mr = calloc(1 + p->n, sizeof(int));++    /* reset cover indices */+    for (i = 1; i <= n; i++) {+        if (p->s[i] == UNASSIGNED) {+            ri[i] = UNCOVERED;+            mr[i] = MARKED;+        } else {+            ri[i] = COVERED;+        }+        ci[i] = UNCOVERED;+    }++    while (TRUE) {+        /* find marked row */+        r = 0;+        for (i = 1; i <= n; i++)+            if (mr[i] == MARKED) {+                r = i;+                break;+            }++        if (r == 0) {+            break;+        }+        for (i = 1; i <= n; i++)+            if (p->c[r][i] == 0 && ci[i] == UNCOVERED) {+                if (p->f[i]) {+                    ri[p->f[i]] = UNCOVERED;+                    mr[p->f[i]] = MARKED;+                    ci[i] = COVERED;+                } else {+                    if (p->s[r] == UNASSIGNED) {+                        ++p->na;+                    }++                    p->f[p->s[r]] = 0;+                    p->f[i] = r;+                    p->s[r] = i;++                    free(mr);+                    return NOREDUCE;+                }+            }+        mr[r] = UNMARKED;+    }+    free(mr);+    return REDUCE;+}++void reduce(AP *p, int *ri, int *ci) {+    int i, j, n;+    double min;++    n = p->n;++    /* find minimum in uncovered c-matrix */+    min = DBL_MAX;+    for (i = 1; i <= n; i++)+        for (j = 1; j <= n; j++)+            if (ri[i] == UNCOVERED && ci[j] == UNCOVERED) {+                if (p->c[i][j] < min) {+                    min = p->c[i][j];+                }+            }++    /* subtract min from each uncovered element and add it to each element */+    /* which is covered twice                                              */+    for (i = 1; i <= n; i++)+        for (j = 1; j <= n; j++) {+            if (ri[i] == UNCOVERED && ci[j] == UNCOVERED) {+                p->c[i][j] -= min;+            }+            if (ri[i] == COVERED && ci[j] == COVERED) {+                p->c[i][j] += min;+            }+        }+}++void preassign(AP *p) {+    int i, j, min, r, c, n, count;+    int *ri, *ci, *rz, *cz;++    n = p->n;+    p->na = 0;++    /* row and column markers */+    ri = calloc(1 + n, sizeof(int));+    ci = calloc(1 + n, sizeof(int));++    /* row and column counts of zeroes */+    rz = calloc(1 + n, sizeof(int));+    cz = calloc(1 + n, sizeof(int));++    for (i = 1; i <= n; i++) {+        count = 0;+        for (j = 1; j <= n; j++)+            if (p->c[i][j] == 0) {+                ++count;+            }+        rz[i] = count;+    }++    for (i = 1; i <= n; i++) {+        count = 0;+        for (j = 1; j <= n; j++)+            if (p->c[j][i] == 0) {+                ++count;+            }+        cz[i] = count;+    }++    while (TRUE) {+        /* find unassigned row with least number of zeroes > 0 */+        min = INT_MAX;+        r = 0;+        for (i = 1; i <= n; i++)+            if (rz[i] > 0 && rz[i] < min && ri[i] == UNASSIGNED) {+                min = rz[i];+                r = i;+            }+        /* check if we are done */+        if (r == 0) {+            break;+        }++        /* find unassigned column in row r with least number of zeroes */+        c = 0;+        min = INT_MAX;+        for (i = 1; i <= n; i++)+            if (p->c[r][i] == 0 && cz[i] < min && ci[i] == UNASSIGNED) {+                min = cz[i];+                c = i;+            }++        if (c) {+            ++p->na;+            p->s[r] = c;+            p->f[c] = r;++            ri[r] = ASSIGNED;+            ci[c] = ASSIGNED;++            /* adjust zero counts */+            cz[c] = 0;+            for (i = 1; i <= n; i++)+                if (p->c[i][c] == 0) {+                    --rz[i];+                }+        }+    }++    /* free memory */+    free(ri);+    free(ci);+    free(rz);+    free(cz);+}++void preprocess(AP *p) {+    int i, j, n;+    double min;++    n = p->n;++    /* subtract column minima in each row */+    for (i = 1; i <= n; i++) {+        min = p->c[i][1];+        for (j = 2; j <= n; j++)+            if (p->c[i][j] < min) {+                min = p->c[i][j];+            }+        for (j = 1; j <= n; j++) {+            p->c[i][j] -= min;+        }+    }++    /* subtract row minima in each column */+    for (i = 1; i <= n; i++) {+        min = p->c[1][i];+        for (j = 2; j <= n; j++)+            if (p->c[j][i] < min) {+                min = p->c[j][i];+            }+        for (j = 1; j <= n; j++) {+            p->c[j][i] -= min;+        }+    }+}++int igraph_solve_lsap(igraph_matrix_t *c, igraph_integer_t n,+                      igraph_vector_int_t *p) {+    AP *ap;++    IGRAPH_CHECK(igraph_vector_int_resize(p, n));+    igraph_vector_int_null(p);++    ap = ap_create_problem(&MATRIX(*c, 0, 0), n);+    ap_hungarian(ap);+    ap_assignment(ap, VECTOR(*p));+    ap_free(ap);++    return 0;+}
+ igraph/src/lwrite.c view
@@ -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
+ igraph/src/matching.c view
@@ -0,0 +1,1025 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2012  Tamas Nepusz <ntamas@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 {+        IGRAPH_CHECK(igraph_i_maximum_bipartite_matching_weighted(graph, types,+                     matching_size, matching_weight, matching, weights, eps));+        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* 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 (VECTOR(*types)[k] == VECTOR(*types)[i]) {+                IGRAPH_ERROR("Graph is not bipartite with supplied types vector", IGRAPH_EINVAL);+            }+            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_type;   /* denotes which part of the bipartite graph is smaller */+    igraph_vector_t smaller_set;      /* stores the vertex IDs of the smaller set */+    igraph_vector_t larger_set;       /* stores the vertex IDs of the larger set */+    long int smaller_set_size;        /* size of the smaller set */+    long int larger_set_size;         /* size of the larger 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_int_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);+    IGRAPH_VECTOR_INIT_FINALLY(&smaller_set, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&larger_set, 0);++    /* (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_type = (j > no_of_nodes / 2);+    smaller_set_size = smaller_set_type ? (no_of_nodes - j) : j;+    larger_set_size = no_of_nodes - smaller_set_size;+    IGRAPH_CHECK(igraph_vector_reserve(&smaller_set, smaller_set_size));+    IGRAPH_CHECK(igraph_vector_reserve(&larger_set, larger_set_size));+    for (i = 0; i < no_of_nodes; i++) {+        if (VECTOR(*types)[i] == smaller_set_type) {+            IGRAPH_CHECK(igraph_vector_push_back(&smaller_set, i));+        } else {+            IGRAPH_CHECK(igraph_vector_push_back(&larger_set, i));+        }+    }++    /* (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_type) {+            VECTOR(labels)[i] = 0;+            continue;+        }++        neis = igraph_inclist_get(&inclist, i);+        n = igraph_vector_int_size(neis);+        for (j = 0, k = 0; j < n; j++) {+            k = (long int) VECTOR(*neis)[j];+            u = IGRAPH_OTHER(graph, k, i);+            if (VECTOR(*types)[u] == VECTOR(*types)[i]) {+                IGRAPH_ERROR("Graph is not bipartite with supplied types vector", IGRAPH_EINVAL);+            }+            if (VECTOR(*weights)[k] > max_weight) {+                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 (j = 0; j < smaller_set_size; j++) {+            i = VECTOR(smaller_set)[j];+            if (UNMATCHED(i)) {+                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_int_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 (j = 0; j < larger_set_size; j++) {+            i = VECTOR(larger_set)[j];+            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_int_size(neis);+            for (j = 0; j < k; j++) {+                /* v is the vertex sitting at the other end of an edge incident+                 * on u; check whether it was reached */+                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_int_size(neis);+                for (j = 0; j < k; j++) {+                    debug("  Decreasing slack of edge %ld (%ld--%ld) by %.4f\n",+                          (long)VECTOR(*neis)[j], (long)u,+                          (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_int_size(neis);+                for (j = 0; j < k; j++) {+                    debug("  Increasing slack of edge %ld (%ld--%ld) by %.4f\n",+                          (long)VECTOR(*neis)[j], (long)u,+                          (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 (i = 0; i < smaller_set_size; i++) {+            u = VECTOR(smaller_set)[i];+            for (j = 0; j < larger_set_size; j++) {+                v = VECTOR(larger_set)[j];+                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, &k)) {+                        debug("New tight phantom edge: %ld -- %ld\n", (long)u, (long)v);+                        IGRAPH_CHECK(igraph_vector_int_insert(neis2, k, 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 < smaller_set_size; i++) {+        u = VECTOR(smaller_set)[i];+        v = VECTOR(match)[u];+        if (v != -1) {+            neis2 = igraph_adjlist_get(&tight_phantom_edges, u);+            if (igraph_vector_int_binsearch(neis2, v, 0)) {+                VECTOR(match)[u] = VECTOR(match)[v] = -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_vector_destroy(&larger_set);+    igraph_vector_destroy(&smaller_set);+    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(11);++    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++
+ igraph/src/math.c view
@@ -0,0 +1,326 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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;+}++/**+ * \function igraph_almost_equals+ * Compare two double-precision floats with a tolerance+ *+ * Determines whether two double-precision floats are "almost equal"+ * to each other with a given level of tolerance on the relative error.+ *+ * \param  a  the first float+ * \param  b  the second float+ * \param  eps  the level of tolerance on the relative error. The relative+ *         error is defined as \c "abs(a-b) / (abs(a) + abs(b))". The+ *         two numbers are considered equal if this is less than \c eps.+ *+ * \return nonzero if the two floats are nearly equal to each other within+ *         the given level of tolerance, zero otherwise+ */+int igraph_almost_equals(double a, double b, double eps) {+    return igraph_cmp_epsilon(a, b, eps) == 0 ? 1 : 0;+}+++/**+ * \function igraph_cmp_epsilon+ * Compare two double-precision floats with a tolerance+ *+ * Determines whether two double-precision floats are "almost equal"+ * to each other with a given level of tolerance on the relative error.+ *+ * \param  a  the first float+ * \param  b  the second float+ * \param  eps  the level of tolerance on the relative error. The relative+ *         error is defined as \c "abs(a-b) / (abs(a) + abs(b))". The+ *         two numbers are considered equal if this is less than \c eps.+ *+ * \return zero if the two floats are nearly equal to each other within+ *         the given level of tolerance, positive number if the first float is+ *         larger, negative number if the second float is larger+ */+int igraph_cmp_epsilon(double a, double b, double eps) {+    double diff;+    double abs_diff;++    if (a == b) {+        /* shortcut, handles infinities */+        return 0;+    }++    diff = a - b;+    abs_diff = fabs(diff);++    if (a == 0 || b == 0 || diff < DBL_MIN) {+        /* a or b is zero or both are extremely close to it; relative+         * error is less meaningful here so just compare it with+         * epsilon */+        return abs_diff < (eps * DBL_MIN) ? 0 : (diff < 0 ? -1 : 1);+    } else {+        /* use relative error */+        return (abs_diff / (fabs(a) + fabs(b)) < eps) ? 0 : (diff < 0 ? -1 : 1);+    }+}+
+ igraph/src/matrix.c view
@@ -0,0 +1,158 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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);+}++int igraph_matrix_zapsmall(igraph_matrix_t *m, igraph_real_t tol) {+    return igraph_vector_zapsmall(&m->data, tol);+}
+ igraph/src/maximal_cliques.c view
@@ -0,0 +1,496 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 an \c igraph_integer_t; the number of maximal+ *   cliques will be stored here.+ * \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+++/**+ * \function igraph_maximal_cliques_callback+ * \brief Finds maximal cliques in a graph and calls a function for each one+ *+ * This function enumerates all maximal cliques within the given size range+ * and calls \p cliquehandler_fn for each of them. The cliques are passed to the+ * callback function as an <type>igraph_vector_t *</type>.  Destroying and+ * freeing this vector is left up to the user.  Use \ref igraph_vector_destroy()+ * to destroy it first, then free it using \ref igraph_free().+ *+ * </para><para>+ *+ * Edge directions are ignored.+ *+ * </para><para>+ *+ * \param graph The input graph.+ * \param cliquehandler_fn Callback function to be called for each clique.+ * See also \ref igraph_clique_handler_t.+ * \param arg Extra argument to supply to \p cliquehandler_fn.+ * \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.+ *+ */++int igraph_maximal_cliques_callback(const igraph_t *graph,+                                    igraph_clique_handler_t *cliquehandler_fn, void *arg,+                                    igraph_integer_t min_size, igraph_integer_t max_size);++#define IGRAPH_MC_CALLBACK+#include "maximal_cliques_template.h"+#undef IGRAPH_MC_CALLBACK+++/**+ * \function igraph_maximal_cliques_hist+ * \brief Count the number of maximal cliques of each size in a graph.+ *+ * This function counts how many maximal cliques of each size are present in+ * the graph. Size-1 maximal cliques are simply isolated vertices.+ *+ * </para><para>+ *+ * Edge directions are ignored.+ *+ * </para><para>+ *+ * \param graph The input graph.+ * \param hist Pointer to an initialized vector. The result will be stored+ * here. The first element will store the number of size-1 maximal cliques,+ * the second element the number of size-2 maximal cliques, etc.+ * For cliques smaller than \c min_size, zero counts will be returned.+ * \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.+ *+ */++int igraph_maximal_cliques_hist(const igraph_t *graph,+                                igraph_vector_t *hist,+                                igraph_integer_t min_size,+                                igraph_integer_t max_size);++#define IGRAPH_MC_HIST+#include "maximal_cliques_template.h"+#undef IGRAPH_MC_HIST
+ igraph/src/memory.c view
@@ -0,0 +1,99 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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).+ *+ * \sa \ref igraph_malloc()+ */++int igraph_free(void *p) {+    igraph_Free(p);+    return 0;+}+++/**+ * \function igraph_malloc+ * Allocate memory that can be safely deallocated by igraph functions+ *+ * Some igraph functions, such as \ref igraph_vector_ptr_free_all() and+ * \ref igraph_vector_ptr_destroy_all() can free memory that may have been+ * allocated by the user.  \c igraph_malloc() works exactly like \c malloc()+ * from the C standard library, but it is guaranteed that it can be safely+ * paired with the \c free() function used by igraph internally (which is+ * also user-accessible through \ref igraph_free()).+ *+ * \param n Number of bytes to be allocated.+ * \return Pointer to the piece of allocated memory.+ *+ * \sa \ref igraph_free()+ */++void *igraph_malloc(size_t n) {+    return malloc(n);+}
+ igraph/src/microscopic_update.c view
@@ -0,0 +1,1209 @@+/* -*- mode: C -*-  */+/*+  Microscopic update rules for dealing with agent-level strategy revision.+  Copyright (C) 2011 Minh Van Nguyen <nguyenminh2@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);++    /* Pop V, A and es from the finally stack -- that's three items */+    IGRAPH_FINALLY_CLEAN(3);++    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);++    /* Pop V, A and vs from the finally stack -- that's three items */+    IGRAPH_FINALLY_CLEAN(3);++    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 &amp; 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;+}
+ igraph/src/mixing.c view
@@ -0,0 +1,300 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/motifs.c view
@@ -0,0 +1,1126 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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; \ref igraph_subisomorphic_lad() for finding+ * subgraphs on more than 4 vertices.+ *+ * 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 (igraph_vector_size(cut_prob) < size) {+        IGRAPH_ERROR("The size of the cut probability vector must not be smaller than the motif size.",+                     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. In case of an integer overflow (i.e. too many+ *    null dyads), -1 will be returned.+ * \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 -1");+        *null = -1;+    } else {+        *null = *null - (*mut) - (*asym);+    }++    return 0;+}++/**+ * \function igraph_triad_census_24+ * TODO+ */++int igraph_triad_census_24(const igraph_t *graph, igraph_real_t *res2,+                           igraph_real_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&lt;->B, C, a graph with a mutual connection between two vertices.+ * \cli 021D+ *      A&lt;-B->C, the binary out-tree.+ * \cli 021U+ *      A->B&lt;-C, the binary in-tree.+ * \cli 021C+ *      A->B->C, the directed line.+ * \cli 111D+ *      A&lt;->B&lt;-C.+ * \cli 111U+ *      A&lt;->B->C.+ * \cli 030T+ *      A->B&lt;-C, A->C.+ * \cli 030C+ *      A&lt;-B&lt;-C, A->C.+ * \cli 201+ *      A&lt;->B&lt;->C.+ * \cli 120D+ *      A&lt;-B->C, A&lt;->C.+ * \cli 120U+ *      A->B&lt;-C, A&lt;->C.+ * \cli 120C+ *      A->B->C, A&lt;->C.+ * \cli 210+ *      A->B&lt;->C, A&lt;->C.+ * \cli 300+ *      A&lt;->B&lt;->C, A&lt;->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_real_t m2, m4;+    igraph_vector_t tmp;+    igraph_integer_t vc = igraph_vcount(graph);+    igraph_real_t total;++    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_vector_null(res);+    IGRAPH_CHECK(igraph_motifs_randesu(graph, &tmp, 3, &cut_prob));+    IGRAPH_CHECK(igraph_triad_census_24(graph, &m2, &m4));++    total = ((igraph_real_t)vc) * (vc - 1);+    total *= (vc - 2);+    total /= 6;++    /* Reorder */+    if (igraph_is_directed(graph)) {+        VECTOR(tmp)[0] = 0;+        VECTOR(tmp)[1] = m2;+        VECTOR(tmp)[3] = m4;+        VECTOR(tmp)[0] = total - igraph_vector_sum(&tmp);++        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];+    } else {+        VECTOR(tmp)[0] = 0;+        VECTOR(tmp)[1] = m2;+        VECTOR(tmp)[0] = total - igraph_vector_sum(&tmp);++        VECTOR(*res)[0] = VECTOR(tmp)[0];+        VECTOR(*res)[2] = VECTOR(tmp)[1];+        VECTOR(*res)[10] = VECTOR(tmp)[2];+        VECTOR(*res)[15] = VECTOR(tmp)[3];+    }++    igraph_vector_destroy(&cut_prob);+    igraph_vector_destroy(&tmp);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}+
+ igraph/src/open.c view
@@ -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
+ igraph/src/operators.c view
@@ -0,0 +1,1243 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_int_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_int_size(nei1) - 1;+        n2 = igraph_vector_int_size(nei2) - 1;+        while (n1 >= 0 && n2 >= 0) {+            e1 = (long int) VECTOR(*nei1)[n1];+            e2 = (long int) VECTOR(*nei2)[n2];+            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_int_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;+}
+ igraph/src/optimal_modularity.c view
@@ -0,0 +1,260 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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++}+
+ igraph/src/options.c view
@@ -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;+}+
+ igraph/src/orbit.cc view
@@ -0,0 +1,144 @@+#include <stdlib.h>+#include <assert.h>+#include "defs.hh"+#include "orbit.hh"++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++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)+{++  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)+{++  merge_orbits(in_orbit[e1], in_orbit[e2]);+}+++bool Orbit::is_minimal_representative(unsigned int element) const+{+  return(get_minimal_representative(element) == element);+}+++unsigned int Orbit::get_minimal_representative(unsigned int element) const+{++  OrbitEntry * const orbit = in_orbit[element];++  return(orbit->element);+}+++unsigned int Orbit::orbit_size(unsigned int element) const+{+  +  return(in_orbit[element]->size);+}+++} // namespace bliss
+ igraph/src/other.c view
@@ -0,0 +1,427 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_vector_t angles, stack, 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;+    }++    IGRAPH_VECTOR_INIT_FINALLY(&angles, no_of_nodes);+    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 */+            VECTOR(angles)[i] = 10;+        } else {+            VECTOR(angles)[i] = atan2(MATRIX(*data, i, 1) - py, MATRIX(*data, i, 0) - px);+        }+    }++    /* Sort points by angles */+    IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);+    IGRAPH_CHECK(igraph_vector_qsort_ind(&angles, &order, 0));++    /* Check if two points have the same angle. If so, keep only the point that+     * is farthest from the pivot */+    j = 0;+    last_idx = (long int) VECTOR(order)[0];+    pivot_idx = (long int) VECTOR(order)[no_of_nodes - 1];+    for (i = 1; i < no_of_nodes; i++) {+        next_idx = (long int) VECTOR(order)[i];+        if (VECTOR(angles)[last_idx] == VECTOR(angles)[next_idx]) {+            /* Keep the vertex that is farther from the pivot, drop the one that is+             * closer */+            px = pow(MATRIX(*data, last_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) ++                 pow(MATRIX(*data, last_idx, 1) - MATRIX(*data, pivot_idx, 1), 2);+            py = pow(MATRIX(*data, next_idx, 0) - MATRIX(*data, pivot_idx, 0), 2) ++                 pow(MATRIX(*data, next_idx, 1) - MATRIX(*data, pivot_idx, 1), 2);+            if (px > py) {+                VECTOR(order)[i] = -1;+            } else {+                VECTOR(order)[j] = -1;+                last_idx = next_idx;+                j = i;+            }+        } else {+            last_idx = next_idx;+            j = i;+        }+    }++    j = 0;+    last_idx = -1;+    before_last_idx = -1;+    while (!igraph_vector_empty(&order)) {+        next_idx = (long int)VECTOR(order)[igraph_vector_size(&order) - 1];+        if (next_idx < 0) {+            /* This vertex should be skipped; was excluded in an earlier step */+            igraph_vector_pop_back(&order);+            continue;+        }+        /* Determine whether we are at a left or right turn */+        if (j < 2) {+            /* Pretend that we are turning into the right direction if we have less+             * than two items in the stack */+            cp = -1;+        } else {+            cp = (MATRIX(*data, last_idx, 0) - MATRIX(*data, before_last_idx, 0)) *+                 (MATRIX(*data, next_idx, 1) - MATRIX(*data, before_last_idx, 1)) -+                 (MATRIX(*data, next_idx, 0) - MATRIX(*data, before_last_idx, 0)) *+                 (MATRIX(*data, last_idx, 1) - MATRIX(*data, before_last_idx, 1));+        }+        /*+        printf("B L N cp: %ld, %ld, %ld, %f [", before_last_idx, last_idx, next_idx, (float)cp);+        for (int k=0; k<j; k++) printf("%ld ", (long)VECTOR(stack)[k]);+        printf("]\n");+        */+        if (cp < 0) {+            /* We are turning into the right direction */+            igraph_vector_pop_back(&order);+            IGRAPH_CHECK(igraph_vector_push_back(&stack, next_idx));+            before_last_idx = last_idx;+            last_idx = next_idx;+            j++;+        } else {+            /* No, skip back and try again in the next iteration */+            igraph_vector_pop_back(&stack);+            j--;+            last_idx = before_last_idx;+            before_last_idx = (j >= 2) ? (long int) VECTOR(stack)[j - 2] : -1;+        }+    }++    /* 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(&order);+    igraph_vector_destroy(&stack);+    igraph_vector_destroy(&angles);+    IGRAPH_FINALLY_CLEAN(3);++    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;+}
+ igraph/src/partition.cc view
@@ -0,0 +1,1143 @@+#include <assert.h>+#include <vector>+#include <list>+#include "graph.hh"+#include "partition.hh"++/* use 'and' instead of '&&' */+#if _MSC_VER+#include <ciso646>+#endif++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++Partition::Partition()+{+  N = 0;+  elements = 0;+  in_pos = 0;+  invariant_values = 0;+  cells = 0;+  free_cells = 0;+  element_to_cell_map = 0;+  graph = 0;+  discrete_cell_count = 0;+  /* Initialize a distribution count sorting array. */+  for(unsigned int i = 0; i < 256; i++)+    dcs_count[i] = 0;++  cr_enabled = false;+  cr_cells = 0;+  cr_levels = 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; }+  N = 0;+}++++void Partition::init(const unsigned int M)+{+  assert(M > 0);+  N = M;++  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].prev = 0;+  cells[0].next = 0;+  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;+      discrete_cell_count = 1;+    }+  else+    {+      first_nonsingleton_cell = &cells[0];+      discrete_cell_count = 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].prev = 0;+      cells[i].next = (i < N-1)?&cells[i+1]:0;+      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);++  /* Reset the main backtracking stack */+  bt_stack.clear();+}+++++++Partition::BacktrackPoint+Partition::set_backtrack_point()+{+  BacktrackInfo info;+  info.refinement_stack_size = refinement_stack.size();+  if(cr_enabled)+    info.cr_backtrack_point = cr_get_backtrack_point();+  BacktrackPoint p = bt_stack.size();+  bt_stack.push_back(info);+  return p;+}++++void+Partition::goto_backtrack_point(BacktrackPoint p)+{+  BacktrackInfo info = bt_stack[p];+  bt_stack.resize(p);++  if(cr_enabled)+    cr_goto_backtrack_point(info.cr_backtrack_point);++  const unsigned int dest_refinement_stack_size = info.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;+      Cell* cell = get_cell(elements[first]);+      +      if(cell->first != first)+	{+	  assert(cell->first < first);+	  assert(cell->split_level <= dest_refinement_stack_size);+	  goto done;+	}+      assert(cell->split_level > dest_refinement_stack_size);++      while(cell->split_level > dest_refinement_stack_size)+	{+	  assert(cell->prev);+	  cell = cell->prev;+	}+      while(cell->next and+	    cell->next->split_level > dest_refinement_stack_size)+	{+	  /* Merge next cell */+	  Cell* const next_cell = cell->next;+	  if(cell->length == 1)+	    discrete_cell_count--;+	  if(next_cell->length == 1)+	    discrete_cell_count--;+	  /* Update element_to_cell_map values of elements added in cell */+	  unsigned int* ep = elements + next_cell->first;+	  unsigned int* const lp = ep + next_cell->length;+	  for( ; ep < lp; ep++)+	    element_to_cell_map[*ep] = cell;+	  /* Update cell parameters */+	  cell->length += next_cell->length;+	  if(next_cell->next)+	    next_cell->next->prev = cell;+	  cell->next = next_cell->next;+	  /* (Pseudo)free next_cell */+	  next_cell->first = 0;+	  next_cell->length = 0;+	  next_cell->prev = 0;+	  next_cell->next = free_cells;+	  free_cells = next_cell;+	}++    done:+      if(i.prev_nonsingleton_first >= 0)+	{+	  Cell* const prev_cell = get_cell(elements[i.prev_nonsingleton_first]);+	  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 = get_cell(elements[i.next_nonsingleton_first]);+	  cell->next_nonsingleton = next_cell;+	  next_cell->prev_nonsingleton = cell;+	}+      else+	{+	  //assert(cell->next_nonsingleton == 0);+	  cell->next_nonsingleton = 0;+	}+    }++}++++Partition::Cell*+Partition::individualize(Partition::Cell * const cell,+			 const unsigned int element)+{++  unsigned int * const pos = in_pos[element];++  const unsigned int last = cell->first + cell->length - 1;+  *pos = elements[last];+  in_pos[*pos] = pos;+  elements[last] = element;+  in_pos[element] = elements + last;+  +  Partition::Cell * const new_cell = aux_split_in_two(cell, cell->length-1);+  element_to_cell_map[element] = new_cell;++  return new_cell;+} ++++Partition::Cell*+Partition::aux_split_in_two(Partition::Cell* const cell,+			    const unsigned int first_half_size)+{+  RefInfo i;+++  /* (Pseudo)allocate new cell */+  Cell * const new_cell = free_cells;+  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 = new_cell;+  new_cell->prev = cell;+  new_cell->split_level = refinement_stack.size()+1;+  /* Update old, splitted cell parameters */+  cell->length = first_half_size;+  cell->next = new_cell;+  /* CR */+  if(cr_enabled)+    cr_create_at_level_trailed(new_cell->first, cr_get_level(cell->first));++  /* Add cell in refinement_stack for backtracking */+  i.split_cell_first = new_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;+      discrete_cell_count++;+    }++  if(cell->is_unit())+    {+      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;+      discrete_cell_count++;+    }++  return new_cell;+} ++++size_t+Partition::print(FILE* const fp, const bool add_newline) const+{+  size_t r = 0;+  const char* cell_sep = "";+  r += fprintf(fp, "[");+  for(Cell* cell = first_cell; cell; cell = cell->next)+    {+      /* Print cell */+      r += fprintf(fp, "%s{", cell_sep);+      cell_sep = ",";+      const char* elem_sep = "";+      for(unsigned int i = 0; i < cell->length; i++)+	{+	  r += fprintf(fp, "%s%u", elem_sep, elements[cell->first + i]);+	  elem_sep = ",";+	}+      r += fprintf(fp, "}");+    }+  r += fprintf(fp, "]");+  if(add_newline) r += fprintf(fp, "\n");+  return r;+}++++size_t+Partition::print_signature(FILE* const fp, const bool add_newline) const+{+  size_t r = 0;+  const char* cell_sep = "";+  r += fprintf(fp, "[");+  for(Cell* cell = first_cell; cell; cell = cell->next)+    {+      if(cell->is_unit()) continue;+      //fprintf(fp, "%s%u", cell_sep, cr_cells[cell->first].level);+      r += fprintf(fp, "%s%u", cell_sep, cell->length);+      cell_sep = ",";+    }+  r += fprintf(fp, "]");+  if(add_newline) r += fprintf(fp, "\n");+  return r;+}++++void+Partition::splitting_queue_add(Cell* const cell)+{+  static const unsigned int smallish_cell_threshold = 1;+  cell->in_splitting_queue = true;+  if(cell->length <= smallish_cell_threshold)+    splitting_queue.push_front(cell);+  else+    splitting_queue.push_back(cell);    +}++++void+Partition::splitting_queue_clear()+{+  while(!splitting_queue_is_empty())+    splitting_queue_pop();+}++++++/*+ * Assumes that the invariant values are NOT the same+ * and that the cell contains more than one element+ */+Partition::Cell*+Partition::sort_and_split_cell1(Partition::Cell* const cell)+{+#if defined(BLISS_EXPENSIVE_CONSISTENCY_CHECKS)+  assert(cell->length > 1);+  assert(cell->first + cell->length <= N);+  unsigned int nof_0_found = 0;+  unsigned int nof_1_found = 0;+  for(unsigned int i = cell->first; i < cell->first + cell->length; i++)+    {+      const unsigned int ival = invariant_values[elements[i]];+      assert(ival == 0 or ival == 1);+      if(ival == 0) nof_0_found++;+      else nof_1_found++;+    }+  assert(nof_0_found > 0);+  assert(nof_1_found > 0);+  assert(nof_1_found == cell->max_ival_count);+  assert(nof_0_found + nof_1_found == cell->length);+  assert(cell->max_ival == 1);+#endif+++  /* (Pseudo)allocate new cell */+  Cell* const new_cell = free_cells;+  free_cells = new_cell->next;++#define NEW_SORT1+#ifdef NEW_SORT1+      unsigned int *ep0 = elements + cell->first;+      unsigned int *ep1 = ep0 + cell->length - cell->max_ival_count;+      if(cell->max_ival_count > cell->length / 2)+	{+	  /* There are more ones than zeros, only move zeros */+	  unsigned int * const end = ep0 + cell->length;+	  while(ep1 < end)+	    {+	      while(invariant_values[*ep1] == 0)+		{+		  const unsigned int tmp = *ep1;+		  *ep1 = *ep0;+		  *ep0 = tmp;+		  in_pos[tmp] = ep0;+		  in_pos[*ep1] = ep1;+		  ep0++;+		}+	      element_to_cell_map[*ep1] = new_cell;+	      invariant_values[*ep1] = 0;+	      ep1++;+	    }+	}+      else+	{+	  /* There are more zeros than ones, only move ones */+	  unsigned int * const end = ep1;+	  while(ep0 < end)+	    {+	      while(invariant_values[*ep0] != 0)+		{+		  const unsigned int tmp = *ep0;+		  *ep0 = *ep1;+		  *ep1 = tmp;+		  in_pos[tmp] = ep1;+		  in_pos[*ep0] = ep0;+		  ep1++;+		}+	      ep0++;+	    }+	  ep1 = end;+	  while(ep1 < elements + cell->first + cell->length)+	    {+	      element_to_cell_map[*ep1] = new_cell;+	      invariant_values[*ep1] = 0;+	      ep1++;+	    }+	}+  /* Update new cell parameters */+  new_cell->first = cell->first + cell->length - cell->max_ival_count;+  new_cell->length = cell->length - (new_cell->first - cell->first);+  new_cell->next = cell->next;+  if(new_cell->next)+    new_cell->next->prev = new_cell;+  new_cell->prev = cell;+  new_cell->split_level = refinement_stack.size()+1;+  /* Update old, splitted cell parameters */+  cell->length = new_cell->first - cell->first;+  cell->next = new_cell;+  /* CR */+  if(cr_enabled)+    cr_create_at_level_trailed(new_cell->first, cr_get_level(cell->first));++#else+  /* 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;+      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;+	}+    }+++  /* 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 = new_cell;+  new_cell->prev = cell;+  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 = refinement_stack.size()+1;+  /* CR */+  if(cr_enabled)+    cr_create_at_level_trailed(new_cell->first, cr_get_level(cell->first));++#endif /* ifdef NEW_SORT1*/++  /* Add cell in refinement stack for backtracking */+  {+    RefInfo i;+    i.split_cell_first = new_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;+	discrete_cell_count++;+      }+    if(cell->is_unit())+      {+	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;+	discrete_cell_count++;+      }+    refinement_stack.push(i);+  }+++  /* Add cells in splitting queue */+  if(cell->in_splitting_queue) {+    /* Both cells must be included in splitting_queue in order to have+       refinement to equitable partition */+    splitting_queue_add(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 */+    splitting_queue_add(min_cell);+    if(max_cell->is_unit()) {+      /* Put the "larger" cell also in splitting_queue */+      splitting_queue_add(max_cell);+    }+  }+++  return new_cell;+}++++++/**+ * An auxiliary function for distribution count sorting.+ * Build start array so that+ * dcs_start[0] = 0 and dcs_start[i+1] = dcs_start[i] + dcs_count[i].+ */+void+Partition::dcs_cumulate_count(const unsigned int max) +{+  unsigned int* count_p = dcs_count;+  unsigned int* start_p = dcs_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.+ */+Partition::Cell*+Partition::sort_and_split_cell255(Partition::Cell* const cell,+				  const unsigned int max_ival)+{++  if(cell->is_unit())+    {+      /* Reset invariant value */+      invariant_values[elements[cell->first]] = 0;+      return cell;+    }+  +#ifdef BLISS_CONSISTENCY_CHECKS+  for(unsigned int i = 0; i < 256; i++)+    assert(dcs_count[i] == 0);+#endif++  /*+   * Compute the distribution of invariant values to the count array+   */+  {+    const unsigned int *ep = elements + cell->first;+    const unsigned int ival = invariant_values[*ep];+    dcs_count[ival]++;+    ep++;+#if defined(BLISS_CONSISTENCY_CHECKS)+    bool equal_invariant_values = true;+#endif+    for(unsigned int i = cell->length - 1; i != 0; i--)+      {+	const unsigned int ival2 = invariant_values[*ep];+	dcs_count[ival2]++;+#if defined(BLISS_CONSISTENCY_CHECKS)+	if(ival2 != ival) {+	  equal_invariant_values = false;+	}+#endif+	ep++;+      }+#if defined(BLISS_CONSISTENCY_CHECKS)+    assert(!equal_invariant_values);+    if(equal_invariant_values) {+      assert(dcs_count[ival] == cell->length);+      dcs_count[ival] = 0;+      clear_ivs(cell);+      return cell;+    }+#endif+  }++  /* Build start array */+  dcs_cumulate_count(max_ival);+++  /* Do the sorting */+  for(unsigned int i = 0; i <= max_ival; i++)+    {+      unsigned int *ep = elements + cell->first + dcs_start[i];+      for(unsigned int j = dcs_count[i]; j > 0; j--)+	{+	  while(true)+	    {+	      const unsigned int element = *ep;+	      const unsigned int ival = invariant_values[element];+	      if(ival == i)+		break;+	      *ep = elements[cell->first + dcs_start[ival]];+	      elements[cell->first + dcs_start[ival]] = element;+	      dcs_start[ival]++;+	      dcs_count[ival]--;+	    }+	  ep++;+	}+      dcs_count[i] = 0;+    }++#if defined(BLISS_CONSISTENCY_CHECKS)+  for(unsigned int i = 0; i < 256; i++)+    assert(dcs_count[i] == 0);+#endif++  /* split cell */+  Cell* const new_cell = split_cell(cell);+  return new_cell;+}++++/*+ * 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(Partition::Cell* const cell)+{+  unsigned int h;+  unsigned int* ep;+++  if(cell->is_unit())+    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];+    ep++;+    for(unsigned int i = cell->length - 1; i > 0; i--)+      {+	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 and 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.+ */+Partition::Cell*+Partition::split_cell(Partition::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;++  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 and graph->compute_eqref_hash)+	{+	  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->is_in_splitting_queue());+      if(original_cell_was_in_splitting_queue)+	{+	  /* In this case, all new cells are inserted in splitting_queue */+	  assert(cell->is_in_splitting_queue());+	  splitting_queue_add(new_cell);+	}+      else+	{+	  /* Otherwise, we can omit one new cell from splitting_queue */+	  assert(!cell->is_in_splitting_queue());+	  if(largest_new_cell == 0) {+	    largest_new_cell = cell;+	  } else {+	    assert(!largest_new_cell->is_in_splitting_queue());+	    if(cell->length > largest_new_cell->length) {+	      splitting_queue_add(largest_new_cell);+	      largest_new_cell = cell;+	    } else {+	      splitting_queue_add(cell);+	    }+	  }+	}+      /* Process the rest of the cell */+      cell = new_cell;+    }++  +  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)+	{+	  splitting_queue_add(largest_new_cell);+	  largest_new_cell = cell;+	}+      else+	{+	  splitting_queue_add(cell);+	}+      if(largest_new_cell->is_unit())+	{+	  /* Needed in certificate computation */+	  splitting_queue_add(largest_new_cell);+	}+    }++  return cell;+}+++Partition::Cell*+Partition::zplit_cell(Partition::Cell* const cell,+		      const bool max_ival_info_ok)+{++  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 BLISS_CONSISTENCY_CHECKS+  /* Verify max_ival info */+  {+    unsigned int nof_zeros = 0;+    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 == 0)+	  nof_zeros++;+	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, clear 'em */+      if(cell->max_ival > 0)+	clear_ivs(cell);+    }+  else+    {+      /* 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);+	}+      else if(cell->max_ival < 256)+	{+	  /* Specialized splitting for cells with invariant values < 256 */+	  last_new_cell = sort_and_split_cell255(cell, cell->max_ival);+	}+      else+	{+	  /* Generic sorting and splitting */+	  const bool sorted = shellsort_cell(cell);+	  assert(sorted);+	  last_new_cell = split_cell(cell);+	}+    }+  cell->max_ival = 0;+  cell->max_ival_count = 0;+  return last_new_cell;+}++++/*+ *+ * Component recursion specific code+ *+ */+void+Partition::cr_init()+{+  assert(bt_stack.empty());++  cr_enabled = true;++  if(cr_cells) free(cr_cells);+  cr_cells = (CRCell*)malloc(N * sizeof(CRCell));+  if(!cr_cells) {assert(false && "Mem out"); }++  if(cr_levels) free(cr_levels);+  cr_levels = (CRCell**)malloc(N * sizeof(CRCell*));+  if(!cr_levels) {assert(false && "Mem out"); }++  for(unsigned int i = 0; i < N; i++) {+    cr_levels[i] = 0;+    cr_cells[i].level = UINT_MAX;+    cr_cells[i].next = 0;+    cr_cells[i].prev_next_ptr = 0;+  }++  for(const Cell *cell = first_cell; cell; cell = cell->next)+    cr_create_at_level_trailed(cell->first, 0);++  cr_max_level = 0;+}+++void+Partition::cr_free()+{+  if(cr_cells) {free(cr_cells); cr_cells = 0; }+  if(cr_levels) {free(cr_levels); cr_levels = 0; }++  cr_created_trail.clear();+  cr_splitted_level_trail.clear();+  cr_bt_info.clear();+  cr_max_level = 0;++  cr_enabled = false;+}+++unsigned int+Partition::cr_split_level(const unsigned int level,+			  const std::vector<unsigned int>& splitted_cells)+{+  assert(cr_enabled);+  assert(level <= cr_max_level);+  cr_levels[++cr_max_level] = 0;+  cr_splitted_level_trail.push_back(level);++  for(unsigned int i = 0; i < splitted_cells.size(); i++)+    {+      const unsigned int cell_index = splitted_cells[i];+      assert(cell_index < N);+      CRCell& cr_cell = cr_cells[cell_index];+      assert(cr_cell.level == level);+      cr_cell.detach();+      cr_create_at_level(cell_index, cr_max_level);+    }++  return cr_max_level;+}+++unsigned int+Partition::cr_get_backtrack_point()+{+  assert(cr_enabled);+  CR_BTInfo info;+  info.created_trail_index = cr_created_trail.size();+  info.splitted_level_trail_index = cr_splitted_level_trail.size();+  cr_bt_info.push_back(info);+  return cr_bt_info.size()-1;+}+++void+Partition::cr_goto_backtrack_point(const unsigned int btpoint)+{+  assert(cr_enabled);+  assert(btpoint < cr_bt_info.size());+  while(cr_created_trail.size() > cr_bt_info[btpoint].created_trail_index)+    {+      const unsigned int cell_index = cr_created_trail.back();+      cr_created_trail.pop_back();+      CRCell& cr_cell = cr_cells[cell_index];+      assert(cr_cell.level != UINT_MAX);+      assert(cr_cell.prev_next_ptr);+      cr_cell.detach();+    }++  while(cr_splitted_level_trail.size() >+	cr_bt_info[btpoint].splitted_level_trail_index)+    {+      const unsigned int dest_level = cr_splitted_level_trail.back();+      cr_splitted_level_trail.pop_back();+      assert(cr_max_level > 0);+      assert(dest_level < cr_max_level);+      while(cr_levels[cr_max_level]) {+	CRCell *cr_cell = cr_levels[cr_max_level];+	cr_cell->detach();+	cr_create_at_level(cr_cell - cr_cells, dest_level);+      }+      cr_max_level--;+    }+  cr_bt_info.resize(btpoint);+}+++void+Partition::cr_create_at_level(const unsigned int cell_index,+			      const unsigned int level)+{+  assert(cr_enabled);+  assert(cell_index < N);+  assert(level < N);+  CRCell& cr_cell = cr_cells[cell_index];+  assert(cr_cell.level == UINT_MAX);+  assert(cr_cell.next == 0);+  assert(cr_cell.prev_next_ptr == 0);+  if(cr_levels[level])+    cr_levels[level]->prev_next_ptr = &(cr_cell.next);+  cr_cell.next = cr_levels[level];+  cr_levels[level] = &cr_cell;+  cr_cell.prev_next_ptr = &cr_levels[level];+  cr_cell.level = level;+}+++void+Partition::cr_create_at_level_trailed(const unsigned int cell_index,+				      const unsigned int level)+{+  assert(cr_enabled);+  cr_create_at_level(cell_index, level);+  cr_created_trail.push_back(cell_index);+}+++} // namespace bliss
+ igraph/src/paths.c view
@@ -0,0 +1,175 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_interface.h"+#include "igraph_interrupt_internal.h"+#include "igraph_vector_ptr.h"+#include "igraph_iterators.h"+#include "igraph_adjlist.h"+#include "igraph_stack.h"++/**+ * \function igraph_get_all_simple_paths+ * List all simple paths from one source+ *+ * A path is simple, if its vertices are unique, no vertex+ * is visited more than once.+ *+ * </para><para>+ * Note that potentially there are exponentially many+ * paths between two vertices of a graph, and you may+ * run out of memory when using this function, if your+ * graph is lattice-like.+ *+ * </para><para>+ * This function currently ignored multiple and loop edges.+ * \param graph The input graph.+ * \param res Initialized integer vector, all paths are+ *        returned here, separated by -1 markers. The paths+ *        are included in arbitrary order, as they are found.+ * \param from The start vertex.+ * \param to The target vertices.+ * \param cutoff Maximum length of path that is considered. If+ *        negative, paths of all lengths are considered.+ * \param mode The type of the paths to consider, it is ignored+ *        for undirected graphs.+ * \return Error code.+ *+ * Time complexity: O(n!) in the worst case, n is the number of+ * vertices.+ */++int igraph_get_all_simple_paths(const igraph_t *graph,+                                igraph_vector_int_t *res,+                                igraph_integer_t from,+                                const igraph_vs_t to,+                                igraph_integer_t cutoff,+                                igraph_neimode_t mode) {++    igraph_integer_t no_nodes = igraph_vcount(graph);+    igraph_vit_t vit;+    igraph_bool_t toall = igraph_vs_is_all(&to);+    igraph_vector_char_t markto;+    igraph_lazy_adjlist_t adjlist;+    igraph_vector_int_t stack, dist;+    igraph_vector_char_t added;+    igraph_vector_int_t nptr;+    int iteration;++    if (from < 0 || from >= no_nodes) {+        IGRAPH_ERROR("Invalid starting vertex", IGRAPH_EINVAL);+    }++    if (!toall) {+        igraph_vector_char_init(&markto, no_nodes);+        IGRAPH_FINALLY(igraph_vector_char_destroy, &markto);+        IGRAPH_CHECK(igraph_vit_create(graph, to, &vit));+        IGRAPH_FINALLY(igraph_vit_destroy, &vit);+        for (; !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {+            VECTOR(markto)[ IGRAPH_VIT_GET(vit) ] = 1;+        }+        igraph_vit_destroy(&vit);+        IGRAPH_FINALLY_CLEAN(1);+    }++    IGRAPH_CHECK(igraph_vector_char_init(&added, no_nodes));+    IGRAPH_FINALLY(igraph_vector_char_destroy, &added);+    IGRAPH_CHECK(igraph_vector_int_init(&stack, 100));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &stack);+    IGRAPH_CHECK(igraph_vector_int_init(&dist, 100));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &dist);+    IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adjlist, mode,+                                          /*simplify=*/ 1));+    IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adjlist);+    IGRAPH_CHECK(igraph_vector_int_init(&nptr, no_nodes));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &nptr);++    igraph_vector_int_clear(res);++    igraph_vector_int_clear(&stack);+    igraph_vector_int_clear(&dist);+    igraph_vector_int_push_back(&stack, from);+    igraph_vector_int_push_back(&dist, 0);+    VECTOR(added)[from] = 1;+    while (!igraph_vector_int_empty(&stack)) {+        int act = igraph_vector_int_tail(&stack);+        int curdist = igraph_vector_int_tail(&dist);+        igraph_vector_t *neis = igraph_lazy_adjlist_get(&adjlist, act);+        int n = igraph_vector_size(neis);+        int *ptr = igraph_vector_int_e_ptr(&nptr, act);+        igraph_bool_t any;+        igraph_bool_t within_dist;+        int nei;++        if (iteration == 0) {+            IGRAPH_ALLOW_INTERRUPTION();+        }++        within_dist = (curdist < cutoff || cutoff < 0);+        if (within_dist) {+            /* Search for a neighbor that was not yet visited */+            any = 0;+            while (!any && (*ptr) < n) {+                nei = (int) VECTOR(*neis)[(*ptr)];+                any = !VECTOR(added)[nei];+                (*ptr) ++;+            }+        }+        if (within_dist && any) {+            /* There is such a neighbor, add it */+            IGRAPH_CHECK(igraph_vector_int_push_back(&stack, nei));+            IGRAPH_CHECK(igraph_vector_int_push_back(&dist, curdist + 1));+            VECTOR(added)[nei] = 1;+            /* Add to results */+            if (toall || VECTOR(markto)[nei]) {+                IGRAPH_CHECK(igraph_vector_int_append(res, &stack));+                IGRAPH_CHECK(igraph_vector_int_push_back(res, -1));+            }+        } else {+            /* There is no such neighbor, finished with the subtree */+            int up = igraph_vector_int_pop_back(&stack);+            igraph_vector_int_pop_back(&dist);+            VECTOR(added)[up] = 0;+            VECTOR(nptr)[up] = 0;+        }++        iteration++;+        if (iteration >= 10000) {+            iteration = 0;+        }+    }++    igraph_vector_int_destroy(&nptr);+    igraph_lazy_adjlist_destroy(&adjlist);+    igraph_vector_int_destroy(&dist);+    igraph_vector_int_destroy(&stack);+    igraph_vector_char_destroy(&added);+    IGRAPH_FINALLY_CLEAN(5);++    if (!toall) {+        igraph_vector_char_destroy(&markto);+        IGRAPH_FINALLY_CLEAN(1);+    }++    return 0;+}
+ igraph/src/plfit.c view
@@ -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;+}+
+ igraph/src/pottsmodel_2.cpp view
@@ -0,0 +1,2225 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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;+}
+ igraph/src/pow_ci.c view
@@ -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
+ igraph/src/pow_dd.c view
@@ -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
+ igraph/src/pow_di.c view
@@ -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
+ igraph/src/pow_hh.c view
@@ -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
+ igraph/src/pow_ii.c view
@@ -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
+ igraph/src/pow_ri.c view
@@ -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
+ igraph/src/pow_zi.c view
@@ -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
+ igraph/src/pow_zz.c view
@@ -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
+ igraph/src/progress.c view
@@ -0,0 +1,153 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/prpack.cpp view
@@ -0,0 +1,103 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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, "");++    // Delete the personalization vector+    if (v) {+        delete[] 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[(long int)IGRAPH_VIT_GET(vit)];+    }+    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;+}+
+ igraph/src/prpack_base_graph.cpp view
@@ -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]];+        }+    }+}+
+ igraph/src/prpack_igraph_graph.cpp view
@@ -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 +
+ igraph/src/prpack_preprocessed_ge_graph.cpp view
@@ -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;+}+
+ igraph/src/prpack_preprocessed_gs_graph.cpp view
@@ -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;+}+
+ igraph/src/prpack_preprocessed_scc_graph.cpp view
@@ -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;+}+
+ igraph/src/prpack_preprocessed_schur_graph.cpp view
@@ -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;+}+
+ igraph/src/prpack_result.cpp view
@@ -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;+}+
+ igraph/src/prpack_solver.cpp view
@@ -0,0 +1,878 @@+#include "prpack_solver.h"+#include "prpack_utils.h"+#include <cmath>+#include <cstdlib>+#include <cstring>+#include <algorithm>+using namespace prpack;+using namespace std;++void prpack_solver::initialize() {+    geg = NULL;+    gsg = NULL;+    sg = NULL;+    sccg = NULL;+	owns_bg = true;+}++prpack_solver::prpack_solver(const prpack_csc* g) {+    initialize();+    TIME(read_time, bg = new prpack_base_graph(g));+}++prpack_solver::prpack_solver(const prpack_int64_csc* g) {+    initialize();+    TIME(read_time, bg = new prpack_base_graph(g));+}++prpack_solver::prpack_solver(const prpack_csr* g) {+    initialize();+    TIME(read_time, bg = new prpack_base_graph(g));+}++prpack_solver::prpack_solver(const prpack_edge_list* g) {+    initialize();+    TIME(read_time, bg = new prpack_base_graph(g));+}++prpack_solver::prpack_solver(prpack_base_graph* g, bool owns_bg) {+    initialize();+	this->owns_bg = owns_bg;+    TIME(read_time, bg = g);+}++prpack_solver::prpack_solver(const char* filename, const char* format, const bool weighted) {+    initialize();+    TIME(read_time, bg = new prpack_base_graph(filename, format, weighted));+}++prpack_solver::~prpack_solver() {+	if (owns_bg) {+		delete bg;+	}+    delete geg;+    delete gsg;+    delete sg;+    delete sccg;+}++int prpack_solver::get_num_vs() {+    return bg->num_vs;+}++prpack_result* prpack_solver::solve(const double alpha, const double tol, const char* method) {+    return solve(alpha, tol, NULL, NULL, method);+}++prpack_result* prpack_solver::solve(+        const double alpha,+        const double tol,+        const double* u,+        const double* v,+        const char* method) {+    double preprocess_time = 0;+    double compute_time = 0;+    prpack_result* ret = NULL;+    // decide which method to run+    string m;+    if (strcmp(method, "") != 0)+        m = string(method);+    else {+        if (bg->num_vs < 128)+            m = "ge";+        else if (sccg != NULL)+            m = "sccgs";+        else if (sg != NULL)+            m = "sg";+        else+            m = "sccgs";+        if (u != v)+            m += "_uv";+    }+    // run the appropriate method+    if (m == "ge") {+        if (geg == NULL) {+            TIME(preprocess_time, geg = new prpack_preprocessed_ge_graph(bg));+        }+        TIME(compute_time, ret = solve_via_ge(+                alpha,+                tol,+                geg->num_vs,+                geg->matrix,+                u));+    } else if (m == "ge_uv") {+        if (geg == NULL) {+            TIME(preprocess_time, geg = new prpack_preprocessed_ge_graph(bg));+        }+        TIME(compute_time, ret = solve_via_ge_uv(+                alpha,+                tol,+                geg->num_vs,+                geg->matrix,+                geg->d,+                u,+                v));+    } else if (m == "gs") {+        if (gsg == NULL) {+            TIME(preprocess_time, gsg = new prpack_preprocessed_gs_graph(bg));+        }+        TIME(compute_time, ret = solve_via_gs(+                alpha,+                tol,+                gsg->num_vs,+                gsg->num_es,+                gsg->heads,+                gsg->tails,+                gsg->vals,+                gsg->ii,+                gsg->d,+                gsg->num_outlinks,+                u,+                v));+    } else if (m == "gserr") {+        if (gsg == NULL) {+            TIME(preprocess_time, gsg = new prpack_preprocessed_gs_graph(bg));+        }+        TIME(compute_time, ret = solve_via_gs_err(+                alpha,+                tol,+                gsg->num_vs,+                gsg->num_es,+                gsg->heads,+                gsg->tails,+                gsg->ii,+                gsg->num_outlinks,+                u,+                v));+    } else if (m == "sgs") {+        if (sg == NULL) {+            TIME(preprocess_time, sg = new prpack_preprocessed_schur_graph(bg));+        }+        TIME(compute_time, ret = solve_via_schur_gs(+                alpha,+                tol,+                sg->num_vs,+                sg->num_no_in_vs,+                sg->num_no_out_vs,+                sg->num_es,+                sg->heads,+                sg->tails,+                sg->vals,+                sg->ii,+                sg->d,+                sg->num_outlinks,+                u,+                sg->encoding,+                sg->decoding));+    } else if (m == "sgs_uv") {+        if (sg == NULL) {+            TIME(preprocess_time, sg = new prpack_preprocessed_schur_graph(bg));+        }+        TIME(compute_time, ret = solve_via_schur_gs_uv(+                alpha,+                tol,+                sg->num_vs,+                sg->num_no_in_vs,+                sg->num_no_out_vs,+                sg->num_es,+                sg->heads,+                sg->tails,+                sg->vals,+                sg->ii,+                sg->d,+                sg->num_outlinks,+                u,+                v,+                sg->encoding,+                sg->decoding));+    } else if (m == "sccgs") {+        if (sccg == NULL) {+            TIME(preprocess_time, sccg = new prpack_preprocessed_scc_graph(bg));+        }+        TIME(compute_time, ret = solve_via_scc_gs(+                alpha,+                tol,+                sccg->num_vs,+                sccg->num_es_inside,+                sccg->heads_inside,+                sccg->tails_inside,+                sccg->vals_inside,+                sccg->num_es_outside,+                sccg->heads_outside,+                sccg->tails_outside,+                sccg->vals_outside,+                sccg->ii,+                sccg->d,+                sccg->num_outlinks,+                u,+                sccg->num_comps,+                sccg->divisions,+                sccg->encoding,+                sccg->decoding));+    } else if (m == "sccgs_uv") {+        if (sccg == NULL) {+            TIME(preprocess_time, sccg = new prpack_preprocessed_scc_graph(bg));+        }+        TIME(compute_time, ret = solve_via_scc_gs_uv(+                alpha,+                tol,+                sccg->num_vs,+                sccg->num_es_inside,+                sccg->heads_inside,+                sccg->tails_inside,+                sccg->vals_inside,+                sccg->num_es_outside,+                sccg->heads_outside,+                sccg->tails_outside,+                sccg->vals_outside,+                sccg->ii,+                sccg->d,+                sccg->num_outlinks,+                u,+                v,+                sccg->num_comps,+                sccg->divisions,+                sccg->encoding,+                sccg->decoding));+    } else {+        // TODO: throw exception+    }+    ret->method = m.c_str();+    ret->read_time = read_time;+    ret->preprocess_time = preprocess_time;+    ret->compute_time = compute_time;+    ret->num_vs = bg->num_vs;+    ret->num_es = bg->num_es;+    return ret;+}++// VARIOUS SOLVING METHODS ////////////////////////////////////////////////////////////////////////++prpack_result* prpack_solver::solve_via_ge(+        const double alpha,+        const double tol,+        const int num_vs,+        const double* matrix,+        const double* uv) {+    prpack_result* ret = new prpack_result();+    // initialize uv values+    const double uv_const = 1.0/num_vs;+    const int uv_exists = (uv) ? 1 : 0;+    uv = (uv) ? uv : &uv_const;+    // create matrix A+    double* A = new double[num_vs*num_vs];+    for (int i = 0; i < num_vs*num_vs; ++i)+        A[i] = -alpha*matrix[i];+    for (int i = 0; i < num_vs*num_vs; i += num_vs + 1)+        ++A[i];+    // create vector b+    double* b = new double[num_vs];+    for (int i = 0; i < num_vs; ++i)+        b[i] = uv[uv_exists*i];+    // solve and normalize+    ge(num_vs, A, b);+    normalize(num_vs, b);+    // clean up and return+    delete[] A;+    ret->num_es_touched = -1;+    ret->x = b;+    return ret;+}++prpack_result* prpack_solver::solve_via_ge_uv(+        const double alpha,+        const double tol,+        const int num_vs,+        const double* matrix,+        const double* d,+        const double* u,+        const double* v) {+    prpack_result* ret = new prpack_result();+    // initialize u and v values+    const double u_const = 1.0/num_vs;+    const double v_const = 1.0/num_vs;+    const int u_exists = (u) ? 1 : 0;+    const int v_exists = (v) ? 1 : 0;+    u = (u) ? u : &u_const;+    v = (v) ? v : &v_const;+    // create matrix A+    double* A = new double[num_vs*num_vs];+    for (int i = 0; i < num_vs*num_vs; ++i)+        A[i] = -alpha*matrix[i];+    for (int i = 0, inum_vs = 0; i < num_vs; ++i, inum_vs += num_vs)+        for (int j = 0; j < num_vs; ++j)+            A[inum_vs + j] -= alpha*u[u_exists*i]*d[j];+    for (int i = 0; i < num_vs*num_vs; i += num_vs + 1)+        ++A[i];+    // create vector b+    double* b = new double[num_vs];+    for (int i = 0; i < num_vs; ++i)+        b[i] = (1 - alpha)*v[v_exists*i];+    // solve+    ge(num_vs, A, b);+    // clean up and return+    delete[] A;+    ret->num_es_touched = -1;+    ret->x = b;+    return ret;+}++// Vanilla Gauss-Seidel.+prpack_result* prpack_solver::solve_via_gs(+        const double alpha,+        const double tol,+        const int num_vs,+        const int num_es,+        const int* heads,+        const int* tails,+        const double* vals,+        const double* ii,+        const double* d,+        const double* num_outlinks,+        const double* u,+        const double* v) {+    prpack_result* ret = new prpack_result();+    const bool weighted = vals != NULL;+    // initialize u and v values+    const double u_const = 1.0/num_vs;+    const double v_const = 1.0/num_vs;+    const int u_exists = (u) ? 1 : 0;+    const int v_exists = (v) ? 1 : 0;+    u = (u) ? u : &u_const;+    v = (v) ? v : &v_const;+    // initialize the eigenvector (and use personalization vector)+    double* x = new double[num_vs];+    for (int i = 0; i < num_vs; ++i)+        x[i] = 0;+    // initialize delta+    double delta = 0;+    // run Gauss-Seidel+    ret->num_es_touched = 0;+    double err = 1, c = 0;+    do {+        if (weighted) {+            for (int i = 0; i < num_vs; ++i) {+                double new_val = 0;+                const int start_j = tails[i];+                const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;+                for (int j = start_j; j < end_j; ++j)+                    // TODO: might want to use compensation summation for large: end_j - start_j+                    new_val += x[heads[j]]*vals[j];+                new_val = alpha*new_val + (1 - alpha)*v[v_exists*i];+                delta -= alpha*x[i]*d[i];+                new_val += delta*u[u_exists*i];+                new_val /= 1 - alpha*(d[i]*u[u_exists*i] + (1 - d[i])*ii[i]);+                delta += alpha*new_val*d[i];+                COMPENSATED_SUM(err, x[i] - new_val, c);+                x[i] = new_val;+            }+        } else {+            for (int i = 0; i < num_vs; ++i) {+                const double old_val = x[i]*num_outlinks[i];+                double new_val = 0;+                const int start_j = tails[i];+                const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;+                for (int j = start_j; j < end_j; ++j)+                    // TODO: might want to use compensation summation for large: end_j - start_j+                    new_val += x[heads[j]];+                new_val = alpha*new_val + (1 - alpha)*v[v_exists*i];+                if (num_outlinks[i] < 0) {+                    delta -= alpha*old_val;+                    new_val += delta*u[u_exists*i];+                    new_val /= 1 - alpha*u[u_exists*i];+                    delta += alpha*new_val;+                } else {+                    new_val += delta*u[u_exists*i];+                    new_val /= 1 - alpha*ii[i];+                }+                COMPENSATED_SUM(err, old_val - new_val, c);+                x[i] = new_val/num_outlinks[i];+            }+        }+        // update iteration index+        ret->num_es_touched += num_es;+    } while (err >= tol);+    // undo num_outlinks transformation+    if (!weighted)+        for (int i = 0; i < num_vs; ++i)+            x[i] *= num_outlinks[i];+    // return results+    ret->x = x;+    return ret;+}++// Implement a gauss-seidel-like process with a strict error bound+// we return a solution with 1-norm error less than tol.+prpack_result* prpack_solver::solve_via_gs_err(+        const double alpha,+        const double tol,+        const int num_vs,+        const int num_es,+        const int* heads,+        const int* tails,+        const double* ii,+        const double* num_outlinks,+        const double* u,+        const double* v) {+    prpack_result* ret = new prpack_result();+    // initialize u and v values+    const double u_const = 1.0/num_vs;+    const double v_const = 1.0/num_vs;+    const int u_exists = (u) ? 1 : 0;+    const int v_exists = (v) ? 1 : 0;+    u = (u) ? u : &u_const;+    v = (v) ? v : &v_const;+    // Note to Dave, we can't rescale v because we could be running this+    // same routine from multiple threads.+    // initialize the eigenvector (and use personalization vector)+    double* x = new double[num_vs];+    for (int i = 0; i < num_vs; ++i) {+        x[i] = 0.;+    }+    // initialize delta+    double delta = 0.;+    // run Gauss-Seidel, note that we store x/deg[i] throughout this +    // iteration.+    int64_t maxedges = (int64_t)((double)num_es*std::min(+                            log(tol)/log(alpha),+                            (double)PRPACK_SOLVER_MAX_ITERS));+    ret->num_es_touched = 0;+    double err=1., c = 0.;+    do {+        // iterate through vertices+        for (int i = 0; i < num_vs; ++i) {+            double old_val = x[i]*num_outlinks[i]; // adjust back to the "true" value.+            double new_val = 0.;+            int start_j = tails[i], end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;+            for (int j = start_j; j < end_j; ++j) {+                // TODO: might want to use compensation summation for large: end_j - start_j+                new_val += x[heads[j]];+            }+            new_val = alpha*new_val + alpha*ii[i]*old_val + (1.0-alpha)*v[v_exists*i];+            new_val += delta*u[u_exists*i]; // add the dangling node adjustment+            if (num_outlinks[i] < 0) {+                delta += alpha*(new_val - old_val);+            } +            // note that new_val > old_val, but the fabs is just for +            COMPENSATED_SUM(err, -(new_val - old_val), c);+            x[i] = new_val/num_outlinks[i];+        }+        // update iteration index+        ret->num_es_touched += num_es;+    } while (err >= tol && ret->num_es_touched < maxedges);+    if (err >= tol) {+        ret->converged = 0;+    } else {+        ret->converged = 1;+    }+    // undo num_outlinks transformation+    for (int i = 0; i < num_vs; ++i)+        x[i] *= num_outlinks[i];+    // return results+    ret->x = x;+    return ret;+}++// Gauss-Seidel using the Schur complement to separate dangling nodes.+prpack_result* prpack_solver::solve_via_schur_gs(+        const double alpha,+        const double tol,+        const int num_vs,+        const int num_no_in_vs,+        const int num_no_out_vs,+        const int num_es,+        const int* heads,+        const int* tails,+        const double* vals,+        const double* ii,+        const double* d,+        const double* num_outlinks,+        const double* uv,+        const int* encoding,+        const int* decoding,+        const bool should_normalize) {+    prpack_result* ret = new prpack_result();+    const bool weighted = vals != NULL;+    // initialize uv values+    const double uv_const = 1.0/num_vs;+    const int uv_exists = (uv) ? 1 : 0;+    uv = (uv) ? prpack_utils::permute(num_vs, uv, encoding) : &uv_const;+    // initialize the eigenvector (and use personalization vector)+    double* x = new double[num_vs];+    for (int i = 0; i < num_vs - num_no_out_vs; ++i)+        x[i] = uv[uv_exists*i]/(1 - alpha*ii[i])/((weighted) ? 1 : num_outlinks[i]);+    // run Gauss-Seidel for the top left part of (I - alpha*P)*x = uv+    ret->num_es_touched = 0;+    double err, c;+    do {+        // iterate through vertices+        int num_es_touched = 0;+        err = c = 0;+        #pragma omp parallel for firstprivate(c) reduction(+:err, num_es_touched) schedule(dynamic, 64)+        for (int i = num_no_in_vs; i < num_vs - num_no_out_vs; ++i) {+            double new_val = 0;+            const int start_j = tails[i];+            const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;+            if (weighted) {+                for (int j = start_j; j < end_j; ++j)+                    // TODO: might want to use compensation summation for large: end_j - start_j+                    new_val += x[heads[j]]*vals[j];+                COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);+                new_val = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);+                x[i] = new_val;+            } else {+                for (int j = start_j; j < end_j; ++j)+                    // TODO: might want to use compensation summation for large: end_j - start_j+                    new_val += x[heads[j]];+                COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);+                new_val = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);+                x[i] = new_val/num_outlinks[i];+            }+            num_es_touched += end_j - start_j;+        }+        // update iteration index+        ret->num_es_touched += num_es_touched;+    } while (err/(1 - alpha) >= tol);+    // solve for the dangling nodes+    int num_es_touched = 0;+    #pragma omp parallel for reduction(+:num_es_touched) schedule(dynamic, 64)+    for (int i = num_vs - num_no_out_vs; i < num_vs; ++i) {+        x[i] = 0;+        const int start_j = tails[i];+        const int end_j = (i + 1 != num_vs) ? tails[i + 1] : num_es;+        for (int j = start_j; j < end_j; ++j)+            x[i] += x[heads[j]]*((weighted) ? vals[j] : 1);+        x[i] = (alpha*x[i] + uv[uv_exists*i])/(1 - alpha*ii[i]);+        num_es_touched += end_j - start_j;+    }+    ret->num_es_touched += num_es_touched;+    // undo num_outlinks transformation+    if (!weighted)+        for (int i = 0; i < num_vs - num_no_out_vs; ++i)+            x[i] *= num_outlinks[i];+    // normalize x to get the solution for: (I - alpha*P - alpha*u*d')*x = (1 - alpha)*v+    if (should_normalize)+        normalize(num_vs, x);+    // return results+    ret->x = prpack_utils::permute(num_vs, x, decoding);+    delete[] x;+    if (uv_exists)+        delete[] uv;+    return ret;+}++prpack_result* prpack_solver::solve_via_schur_gs_uv(+        const double alpha,+        const double tol,+        const int num_vs,+        const int num_no_in_vs,+        const int num_no_out_vs,+        const int num_es,+        const int* heads,+        const int* tails,+        const double* vals,+        const double* ii,+        const double* d,+        const double* num_outlinks,+        const double* u,+        const double* v,+        const int* encoding,+        const int* decoding) {+    // solve uv = u+    prpack_result* ret_u = solve_via_schur_gs(+            alpha,+            tol,+            num_vs,+            num_no_in_vs,+            num_no_out_vs,+            num_es,+            heads,+            tails,+            vals,+            ii,+            d,+            num_outlinks,+            u,+            encoding,+            decoding,+            false);+    // solve uv = v+    prpack_result* ret_v = solve_via_schur_gs(+            alpha,+            tol,+            num_vs,+            num_no_in_vs,+            num_no_out_vs,+            num_es,+            heads,+            tails,+            vals,+            ii,+            d,+            num_outlinks,+            v,+            encoding,+            decoding,+            false);+    // combine the u and v cases+    return combine_uv(num_vs, d, num_outlinks, encoding, alpha, ret_u, ret_v);+}++/** Gauss-Seidel using strongly connected components.+ * Notes:+ *   If not weighted, then we store x[i] = "x[i]/outdegree" to + *   avoid additional arithmetic.  We don't do this for the weighted+ *   case because the adjustment may not be constant.+ */+prpack_result* prpack_solver::solve_via_scc_gs(+        const double alpha,+        const double tol,+        const int num_vs,+        const int num_es_inside,+        const int* heads_inside,+        const int* tails_inside,+        const double* vals_inside,+        const int num_es_outside,+        const int* heads_outside,+        const int* tails_outside,+        const double* vals_outside,+        const double* ii,+        const double* d,+        const double* num_outlinks,+        const double* uv,+        const int num_comps,+        const int* divisions,+        const int* encoding,+        const int* decoding,+        const bool should_normalize) {+    prpack_result* ret = new prpack_result();+    const bool weighted = vals_inside != NULL;+    // initialize uv values+    const double uv_const = 1.0/num_vs;+    const int uv_exists = (uv) ? 1 : 0;+    uv = (uv) ? prpack_utils::permute(num_vs, uv, encoding) : &uv_const;+    // CHECK initialize the solution with one iteration of GS from x=0.+    double* x = new double[num_vs];+    for (int i = 0; i < num_vs; ++i)+        x[i] = uv[uv_exists*i]/(1 - alpha*ii[i])/((weighted) ? 1 : num_outlinks[i]);+    // create x_outside+    double* x_outside = new double[num_vs];+    // run Gauss-Seidel for (I - alpha*P)*x = uv+    ret->num_es_touched = 0;+    for (int comp_i = 0; comp_i < num_comps; ++comp_i) {+        const int start_comp = divisions[comp_i];+        const int end_comp = (comp_i + 1 != num_comps) ? divisions[comp_i + 1] : num_vs;+        const bool parallelize = end_comp - start_comp > 512;+        // initialize relevant x_outside values+        for (int i = start_comp; i < end_comp; ++i) {+            x_outside[i] = 0;+            const int start_j = tails_outside[i];+            const int end_j = (i + 1 != num_vs) ? tails_outside[i + 1] : num_es_outside;+            for (int j = start_j; j < end_j; ++j)+                x_outside[i] += x[heads_outside[j]]*((weighted) ? vals_outside[j] : 1.);+            ret->num_es_touched += end_j - start_j;+        }+        double err, c;+        do {+            int num_es_touched = 0;+            err = c = 0;+            if (parallelize) {+                // iterate through vertices+                #pragma omp parallel for firstprivate(c) reduction(+:err, num_es_touched) schedule(dynamic, 64)+                for (int i = start_comp; i < end_comp; ++i) {+                    double new_val = x_outside[i];+                    const int start_j = tails_inside[i];+                    const int end_j = (i + 1 != num_vs) ? tails_inside[i + 1] : num_es_inside;+                    if (weighted) {+                        for (int j = start_j; j < end_j; ++j) {+                            // TODO: might want to use compensation summation for large: end_j - start_j+                            new_val += x[heads_inside[j]]*vals_inside[j];+                        }+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);+                    } else {+                        for (int j = start_j; j < end_j; ++j) {+                            // TODO: might want to use compensation summation for large: end_j - start_j+                            new_val += x[heads_inside[j]];+                        }+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i])/num_outlinks[i];+                    }+                    num_es_touched += end_j - start_j;+                }+            } else {+                for (int i = start_comp; i < end_comp; ++i) {+                    double new_val = x_outside[i];+                    const int start_j = tails_inside[i];+                    const int end_j = (i + 1 != num_vs) ? tails_inside[i + 1] : num_es_inside;+                    if (weighted) {+                        for (int j = start_j; j < end_j; ++j) {+                            // TODO: might want to use compensation summation for large: end_j - start_j+                            new_val += x[heads_inside[j]]*vals_inside[j];+                        }+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]), c);+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i]);+                    } else {+                        for (int j = start_j; j < end_j; ++j) {+                            // TODO: might want to use compensation summation for large: end_j - start_j+                            new_val += x[heads_inside[j]];+                        }+                        COMPENSATED_SUM(err, fabs(uv[uv_exists*i] + alpha*new_val - (1 - alpha*ii[i])*x[i]*num_outlinks[i]), c);+                        x[i] = (alpha*new_val + uv[uv_exists*i])/(1 - alpha*ii[i])/num_outlinks[i];+                    }+                    num_es_touched += end_j - start_j;+                }+            }+            // update iteration index+            ret->num_es_touched += num_es_touched;+        } while (err/(1 - alpha) >= tol*(end_comp - start_comp)/num_vs);+    }+    // undo num_outlinks transformation+    if (!weighted)+        for (int i = 0; i < num_vs; ++i)+            x[i] *= num_outlinks[i];+    // normalize x to get the solution for: (I - alpha*P - alpha*u*d')*x = (1 - alpha)*v+    if (should_normalize)+        normalize(num_vs, x);+    // return results+    ret->x = prpack_utils::permute(num_vs, x, decoding);+    delete[] x;+    delete[] x_outside;+    if (uv_exists)+        delete[] uv;+    return ret;+}++prpack_result* prpack_solver::solve_via_scc_gs_uv(+        const double alpha,+        const double tol,+        const int num_vs,+        const int num_es_inside,+        const int* heads_inside,+        const int* tails_inside,+        const double* vals_inside,+        const int num_es_outside,+        const int* heads_outside,+        const int* tails_outside,+        const double* vals_outside,+        const double* ii,+        const double* d,+        const double* num_outlinks,+        const double* u,+        const double* v,+        const int num_comps,+        const int* divisions,+        const int* encoding,+        const int* decoding) {+    // solve uv = u+    prpack_result* ret_u = solve_via_scc_gs(+            alpha,+            tol,+            num_vs,+            num_es_inside,+            heads_inside,+            tails_inside,+            vals_inside,+            num_es_outside,+            heads_outside,+            tails_outside,+            vals_outside,+            ii,+            d,+            num_outlinks,+            u,+            num_comps,+            divisions,+            encoding,+            decoding,+            false);+    // solve uv = v+    prpack_result* ret_v = solve_via_scc_gs(+            alpha,+            tol,+            num_vs,+            num_es_inside,+            heads_inside,+            tails_inside,+            vals_inside,+            num_es_outside,+            heads_outside,+            tails_outside,+            vals_outside,+            ii,+            d,+            num_outlinks,+            v,+            num_comps,+            divisions,+            encoding,+            decoding,+            false);+    // combine u and v+    return combine_uv(num_vs, d, num_outlinks, encoding, alpha, ret_u, ret_v);+}++// VARIOUS HELPER METHODS /////////////////////////////////////////////////////////////////////////++// Run Gaussian-Elimination (note: this changes A and returns the solution in b)+void prpack_solver::ge(const int sz, double* A, double* b) {+    // put into triangular form+    for (int i = 0, isz = 0; i < sz; ++i, isz += sz)+        for (int k = 0, ksz = 0; k < i; ++k, ksz += sz)+            if (A[isz + k] != 0) {+                const double coeff = A[isz + k]/A[ksz + k];+                A[isz + k] = 0;+                for (int j = k + 1; j < sz; ++j)+                    A[isz + j] -= coeff*A[ksz + j];+                b[i] -= coeff*b[k];+            }+    // backwards substitution+    for (int i = sz - 1, isz = (sz - 1)*sz; i >= 0; --i, isz -= sz) {+        for (int j = i + 1; j < sz; ++j)+            b[i] -= A[isz + j]*b[j];+        b[i] /= A[isz + i];+    }+}++// Normalize a vector to sum to 1.+void prpack_solver::normalize(const int length, double* x) {+    double norm = 0, c = 0;+    for (int i = 0; i < length; ++i) {+        COMPENSATED_SUM(norm, x[i], c);+    }+    norm = 1/norm;+    for (int i = 0; i < length; ++i)+        x[i] *= norm;+}++// Combine u and v results.+prpack_result* prpack_solver::combine_uv(+        const int num_vs,+        const double* d,+        const double* num_outlinks,+        const int* encoding,+        const double alpha,+        const prpack_result* ret_u,+        const prpack_result* ret_v) {+    prpack_result* ret = new prpack_result();+    const bool weighted = d != NULL;+    double delta_u = 0;+    double delta_v = 0;+    for (int i = 0; i < num_vs; ++i) {+        if ((weighted) ? (d[encoding[i]] == 1) : (num_outlinks[encoding[i]] < 0)) {+            delta_u += ret_u->x[i];+            delta_v += ret_v->x[i];+        }+    }+    const double s = ((1 - alpha)*alpha*delta_v)/(1 - alpha*delta_u);+    const double t = 1 - alpha;+    ret->x = new double[num_vs];+    for (int i = 0; i < num_vs; ++i)+        ret->x[i] = s*ret_u->x[i] + t*ret_v->x[i];+    ret->num_es_touched = ret_u->num_es_touched + ret_v->num_es_touched;+    // clean up and return+    delete ret_u;+    delete ret_v;+    return ret;+}+
+ igraph/src/prpack_utils.cpp view
@@ -0,0 +1,60 @@+/**+ * @file prpack_utils.cpp+ * An assortment of utility functions for reporting errors, checking time,+ * and working with vectors.+ */++#include <stdlib.h>+#include "prpack_utils.h"+#include <cassert>+#include <iostream>+#include <string>+using namespace prpack;+using namespace std;++#ifdef PRPACK_IGRAPH_SUPPORT+#include "igraph_error.h"+#endif++#if defined(_WIN32) || defined(_WIN64)+#ifndef WIN32_LEAN_AND_MEAN+#define WIN32_LEAN_AND_MEAN+#include <windows.h>+#endif+double prpack_utils::get_time() {+    LARGE_INTEGER t, freq;+    QueryPerformanceCounter(&t);+    QueryPerformanceFrequency(&freq);+    return double(t.QuadPart)/double(freq.QuadPart);+}+#else+#include <sys/types.h>+#include <sys/time.h>+double prpack_utils::get_time() {+    struct timeval t;+    gettimeofday(&t, 0);+    return (t.tv_sec*1.0 + t.tv_usec/1000000.0);+}+#endif++// Fails and outputs 'msg' if 'condition' is false.+void prpack_utils::validate(const bool condition, const string& msg) {+    if (!condition) {+#ifdef PRPACK_IGRAPH_SUPPORT+        igraph_error("Internal error in PRPACK", __FILE__, __LINE__, +	             IGRAPH_EINTERNAL);+#else+        cerr << msg << endl;+        exit(-1);+#endif+    }+}++// Permute a vector.+double* prpack_utils::permute(const int length, const double* a, const int* coding) {+    double* ret = new double[length];+    for (int i = 0; i < length; ++i)+        ret[coding[i]] = a[i];+    return ret;+}+
+ igraph/src/qsort.c view
@@ -0,0 +1,209 @@+/*-+ * 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 _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);*/+}+
+ igraph/src/qsort_r.c view
@@ -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"
+ igraph/src/r_abs.c view
@@ -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
+ igraph/src/r_acos.c view
@@ -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
+ igraph/src/r_asin.c view
@@ -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
+ igraph/src/r_atan.c view
@@ -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
+ igraph/src/r_atn2.c view
@@ -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
+ igraph/src/r_cnjg.c view
@@ -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
+ igraph/src/r_cos.c view
@@ -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
+ igraph/src/r_cosh.c view
@@ -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
+ igraph/src/r_dim.c view
@@ -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
+ igraph/src/r_exp.c view
@@ -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
+ igraph/src/r_imag.c view
@@ -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
+ igraph/src/r_int.c view
@@ -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
+ igraph/src/r_lg10.c view
@@ -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
+ igraph/src/r_log.c view
@@ -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
+ igraph/src/r_mod.c view
@@ -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
+ igraph/src/r_nint.c view
@@ -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
+ igraph/src/r_sign.c view
@@ -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
+ igraph/src/r_sin.c view
@@ -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
+ igraph/src/r_sinh.c view
@@ -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
+ igraph/src/r_sqrt.c view
@@ -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
+ igraph/src/r_tan.c view
@@ -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
+ igraph/src/r_tanh.c view
@@ -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
+ igraph/src/random.c view
@@ -0,0 +1,2500 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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"+#include "igraph_matrix.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,+    /* get_gamma= */ 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,+    /* get_gamma= */ 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,+    /* get_gamma= */ 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);+double  Rf_rgamma(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_gamma(void *state, igraph_real_t shape,+                                     igraph_real_t scale) {+    return Rf_rgamma(shape, scale);+}++igraph_real_t igraph_rng_R_get_exp(void *state, igraph_real_t rate) {+    igraph_real_t scale = 1.0 / rate;+    if (!IGRAPH_FINITE(scale) || scale <= 0.0) {+        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);+double igraph_rgamma(igraph_rng_t *rng, double shape, double scale);++/**+ * \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);+    }+}++/**+ * \function igraph_rng_get_gamma+ * Generate sample from a Gamma distribution+ *+ * \param rng Pointer to the RNG to use. Use \ref igraph_rng_default()+ *        here to use the default igraph RNG.+ * \param shape Shape parameter.+ * \param scale Scale parameter.+ * \return The generated sample+ *+ * Time complexity: depends on RNG.+ */++igraph_real_t igraph_rng_get_gamma(igraph_rng_t *rng, igraph_real_t shape,+                                   igraph_real_t scale) {+    const igraph_rng_type_t *type = rng->type;+    if (type->get_gamma) {+        return type->get_gamma(rng->state, shape, scale);+    } else {+        return igraph_rgamma(rng, shape, scale);+    }+}++unsigned long int igraph_rng_get_int31(igraph_rng_t *rng) {+    const igraph_rng_type_t *type = rng->type;+    unsigned long int max = type->max;+    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 &gt; \c h. (2) Assuming that+ *         \c l &lt; \c h and N is the sample size, the above error code is+ *         returned if N &gt; |\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 = (nreal != 0) ? 1.0 / nreal : 0.0;+    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 == 0) {+        igraph_vector_clear(res);+        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();+}++double igraph_rgamma(igraph_rng_t *rng, double shape, double scale) {+    return Rf_rgamma(shape, scale);+}++#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++#define ML_POSINF IGRAPH_INFINITY+#define ML_NEGINF -IGRAPH_INFINITY+#define ML_NAN    IGRAPH_NAN++#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;+}++#if HAVE_WORKING_ISFINITE || HAVE_ISFINITE+    /* isfinite is defined in <math.h> according to C99 */+    #define R_FINITE(x)    isfinite(x)+#elif HAVE_WORKING_FINITE || HAVE_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) {+#if HAVE_WORKING_ISFINITE || HAVE_ISFINITE+    return isfinite(x);+#elif HAVE_WORKING_FINITE || HAVE_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;+}++#undef a1+#undef a2+#undef a3+#undef a4+#undef a5+#undef a6+#undef a7++double igraph_rgeom(igraph_rng_t *rng, double p) {+    if (ISNAN(p) || p <= 0 || p > 1) {+        ML_ERR_return_NAN;+    }++    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);+}++/*+ *  Mathlib : A C Library of Special Functions+ *  Copyright (C) 1998 Ross Ihaka+ *  Copyright (C) 2000      The R Core Team+ *  Copyright (C) 2003      The R Foundation+ *+ *  This program is free software; you can redistribute it and/or modify+ *  it under the terms of the GNU General Public License as published by+ *  the Free Software Foundation; either version 2 of the License, or+ *  (at your option) any later version.+ *+ *  This program is distributed in the hope that it will be useful,+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+ *  GNU General Public License for more details.+ *+ *  You should have received a copy of the GNU General Public License+ *  along with this program; if not, a copy is available at+ *  http://www.r-project.org/Licenses/+ *+ *  SYNOPSIS+ *+ *      double dnorm4(double x, double mu, double sigma, int give_log)+ *            {dnorm (..) is synonymous and preferred inside R}+ *+ *  DESCRIPTION+ *+ *      Compute the density of the normal distribution.+ */++double igraph_dnorm(double x, double mu, double sigma, int give_log) {+#ifdef IEEE_754+    if (ISNAN(x) || ISNAN(mu) || ISNAN(sigma)) {+        return x + mu + sigma;+    }+#endif+    if (!R_FINITE(sigma)) {+        return R_D__0;+    }+    if (!R_FINITE(x) && mu == x) {+        return ML_NAN;    /* x-mu is NaN */+    }+    if (sigma <= 0) {+        if (sigma < 0) {+            ML_ERR_return_NAN;+        }+        /* sigma == 0 */+        return (x == mu) ? ML_POSINF : R_D__0;+    }+    x = (x - mu) / sigma;++    if (!R_FINITE(x)) {+        return R_D__0;+    }+    return (give_log ?+            -(M_LN_SQRT_2PI  +  0.5 * x * x + log(sigma)) :+            M_1_SQRT_2PI * exp(-0.5 * x * x)  /   sigma);+    /* M_1_SQRT_2PI = 1 / sqrt(2 * pi) */+}++/* This is from nmath/rgamma.c */++/*+ *  Mathlib : A C Library of Special Functions+ *  Copyright (C) 1998 Ross Ihaka+ *  Copyright (C) 2000--2008 The R Core Team+ *+ *  This program is free software; you can redistribute it and/or modify+ *  it under the terms of the GNU General Public License as published by+ *  the Free Software Foundation; either version 2 of the License, or+ *  (at your option) any later version.+ *+ *  This program is distributed in the hope that it will be useful,+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+ *  GNU General Public License for more details.+ *+ *  You should have received a copy of the GNU General Public License+ *  along with this program; if not, a copy is available at+ *  http://www.r-project.org/Licenses/+ *+ *  SYNOPSIS+ *+ *    #include <Rmath.h>+ *    double rgamma(double a, double scale);+ *+ *  DESCRIPTION+ *+ *    Random variates from the gamma distribution.+ *+ *  REFERENCES+ *+ *    [1] Shape parameter a >= 1.  Algorithm GD in:+ *+ *    Ahrens, J.H. and Dieter, U. (1982).+ *    Generating gamma variates by a modified+ *    rejection technique.+ *    Comm. ACM, 25, 47-54.+ *+ *+ *    [2] Shape parameter 0 < a < 1. Algorithm GS in:+ *+ *    Ahrens, J.H. and Dieter, U. (1974).+ *    Computer methods for sampling from gamma, beta,+ *    poisson and binomial distributions.+ *    Computing, 12, 223-246.+ *+ *    Input: a = parameter (mean) of the standard gamma distribution.+ *    Output: a variate from the gamma(a)-distribution+ */++double igraph_rgamma(igraph_rng_t *rng, double a, double scale) {+    /* Constants : */+    const static double sqrt32 = 5.656854;+    const static double exp_m1 = 0.36787944117144232159;/* exp(-1) = 1/e */++    /* Coefficients q[k] - for q0 = sum(q[k]*a^(-k))+     * Coefficients a[k] - for q = q0+(t*t/2)*sum(a[k]*v^k)+     * Coefficients e[k] - for exp(q)-1 = sum(e[k]*q^k)+     */+    const static double q1 = 0.04166669;+    const static double q2 = 0.02083148;+    const static double q3 = 0.00801191;+    const static double q4 = 0.00144121;+    const static double q5 = -7.388e-5;+    const static double q6 = 2.4511e-4;+    const static double q7 = 2.424e-4;++    const static double a1 = 0.3333333;+    const static double a2 = -0.250003;+    const static double a3 = 0.2000062;+    const static double a4 = -0.1662921;+    const static double a5 = 0.1423657;+    const static double a6 = -0.1367177;+    const static double a7 = 0.1233795;++    /* State variables [FIXME for threading!] :*/+    static double aa = 0.;+    static double aaa = 0.;+    static double s, s2, d;    /* no. 1 (step 1) */+    static double q0, b, si, c;/* no. 2 (step 4) */++    double e, p, q, r, t, u, v, w, x, ret_val;++    if (!R_FINITE(a) || !R_FINITE(scale) || a < 0.0 || scale <= 0.0) {+        if (scale == 0.) {+            return 0.;+        }+        ML_ERR_return_NAN;+    }++    if (a < 1.) { /* GS algorithm for parameters a < 1 */+        if (a == 0) {+            return 0.;+        }+        e = 1.0 + exp_m1 * a;+        repeat {+            p = e * igraph_rng_get_unif01(rng);+            if (p >= 1.0) {+                x = -log((e - p) / a);+                if (igraph_exp_rand(rng) >= (1.0 - a) * log(x)) {+                    break;+                }+            } else {+                x = exp(log(p) / a);+                if (igraph_exp_rand(rng) >= x) {+                    break;+                }+            }+        }+        return scale * x;+    }++    /* --- a >= 1 : GD algorithm --- */++    /* Step 1: Recalculations of s2, s, d if a has changed */+    if (a != aa) {+        aa = a;+        s2 = a - 0.5;+        s = sqrt(s2);+        d = sqrt32 - s * 12.0;+    }+    /* Step 2: t = standard normal deviate,+               x = (s,1/2) -normal deviate. */++    /* immediate acceptance (i) */+    t = igraph_norm_rand(rng);+    x = s + 0.5 * t;+    ret_val = x * x;+    if (t >= 0.0) {+        return scale * ret_val;+    }++    /* Step 3: u = 0,1 - uniform sample. squeeze acceptance (s) */+    u = igraph_rng_get_unif01(rng);+    if (d * u <= t * t * t) {+        return scale * ret_val;+    }++    /* Step 4: recalculations of q0, b, si, c if necessary */++    if (a != aaa) {+        aaa = a;+        r = 1.0 / a;+        q0 = ((((((q7 * r + q6) * r + q5) * r + q4) * r + q3) * r+               + q2) * r + q1) * r;++        /* Approximation depending on size of parameter a */+        /* The constants in the expressions for b, si and c */+        /* were established by numerical experiments */++        if (a <= 3.686) {+            b = 0.463 + s + 0.178 * s2;+            si = 1.235;+            c = 0.195 / s - 0.079 + 0.16 * s;+        } else if (a <= 13.022) {+            b = 1.654 + 0.0076 * s2;+            si = 1.68 / s + 0.275;+            c = 0.062 / s + 0.024;+        } else {+            b = 1.77;+            si = 0.75;+            c = 0.1515 / s;+        }+    }+    /* Step 5: no quotient test if x not positive */++    if (x > 0.0) {+        /* Step 6: calculation of v and quotient q */+        v = t / (s + s);+        if (fabs(v) <= 0.25)+            q = q0 + 0.5 * t * t * ((((((a7 * v + a6) * v + a5) * v + a4) * v+                                      + a3) * v + a2) * v + a1) * v;+        else {+            q = q0 - s * t + 0.25 * t * t + (s2 + s2) * log(1.0 + v);+        }+++        /* Step 7: quotient acceptance (q) */+        if (log(1.0 - u) <= q) {+            return scale * ret_val;+        }+    }++    repeat {+        /* Step 8: e = standard exponential deviate+         *  u =  0,1 -uniform deviate+         *  t = (b,si)-double exponential (laplace) sample */+        e = igraph_exp_rand(rng);+        u = igraph_rng_get_unif01(rng);+        u = u + u - 1.0;+        if (u < 0.0) {+            t = b - si * e;+        } else {+            t = b + si * e;+        }+        /* Step  9:  rejection if t < tau(1) = -0.71874483771719 */+        if (t >= -0.71874483771719) {+            /* Step 10:  calculation of v and quotient q */+            v = t / (s + s);+            if (fabs(v) <= 0.25)+                q = q0 + 0.5 * t * t *+                ((((((a7 * v + a6) * v + a5) * v + a4) * v + a3) * v+                  + a2) * v + a1) * v;+            else {+                q = q0 - s * t + 0.25 * t * t + (s2 + s2) * log(1.0 + v);+            }+            /* Step 11:  hat acceptance (h) */+            /* (if q not positive go to step 8) */+            if (q > 0.0) {+                w = expm1(q);+                /*  ^^^^^ original code had approximation with rel.err < 2e-7 */+                /* if t is rejected sample again at step 8 */+                if (c * fabs(u) <= w * exp(e - 0.5 * t * t)) {+                    break;+                }+            }+        }+    } /* repeat .. until  `t' is accepted */+    x = s + 0.5 * t;+    return scale * x * x;+}++#endif++int igraph_rng_get_dirichlet(igraph_rng_t *rng,+                             const igraph_vector_t *alpha,+                             igraph_vector_t *result) {++    igraph_integer_t len = igraph_vector_size(alpha);+    igraph_integer_t j;+    igraph_real_t sum = 0.0;++    if (len < 2) {+        IGRAPH_ERROR("Dirichlet parameter vector too short, must "+                     "have at least two entries", IGRAPH_EINVAL);+    }+    if (igraph_vector_min(alpha) <= 0) {+        IGRAPH_ERROR("Dirichlet concentration parameters must be positive",+                     IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_vector_resize(result, len));++    RNG_BEGIN();++    for (j = 0; j < len; j++) {+        VECTOR(*result)[j] = igraph_rng_get_gamma(rng, VECTOR(*alpha)[j], 1.0);+        sum += VECTOR(*result)[j];+    }+    for (j = 0; j < len; j++) {+        VECTOR(*result)[j] /= sum;+    }++    RNG_END();++    return 0;+}++/**********************************************************+ * Testing purposes                                       *+ *********************************************************/++/* 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; */+/* } */
+ igraph/src/random_walk.c view
@@ -0,0 +1,287 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_paths.h"+#include "igraph_adjlist.h"+#include "igraph_interface.h"+#include "igraph_random.h"+#include "igraph_memory.h"+#include "igraph_interrupt_internal.h"++/**+ * \function igraph_random_walk+ * Perform a random walk on a graph+ *+ * Performs a random walk with a given length on a graph, from the given+ * start vertex. Edge directions are (potentially) considered, depending on+ * the \p mode argument.+ *+ * \param graph The input graph, it can be directed or undirected.+ *   Multiple edges are respected, so are loop edges.+ * \param walk An allocated vector, the result is stored here.+ *   It will be resized as needed.+ * \param start The start vertex for the walk.+ * \param steps The number of steps to take. If the random walk gets+ *   stuck, then the \p stuck argument specifies what happens.+ * \param mode How to walk along the edges in direted graphs.+ *   \c IGRAPH_OUT means following edge directions, \c IGRAPH_IN means+ *   going opposite the edge directions, \c IGRAPH_ALL means ignoring+ *   edge directions. This argument is ignored for undirected graphs.+ * \param stuck What to do if the random walk gets stuck.+ *   \c IGRAPH_RANDOM_WALK_STUCK_RETURN means that the function returns+ *   with a shorter walk; \c IGRAPH_RANDOM_WALK_STUCK_ERROR means+ *   that an error is reported. In both cases \p walk is truncated+ *   to contain the actual interrupted walk.+ * \return Error code.+ *+ * Time complexity: O(l + d), where \c l is the length of the+ * walk, and \c d is the total degree of the visited nodes.+ */+++int igraph_random_walk(const igraph_t *graph, igraph_vector_t *walk,+                       igraph_integer_t start, igraph_neimode_t mode,+                       igraph_integer_t steps,+                       igraph_random_walk_stuck_t stuck) {++    /* TODO:+       - multiple walks potentially from multiple start vertices+       - weights+    */++    igraph_lazy_adjlist_t adj;+    igraph_integer_t vc = igraph_vcount(graph);+    igraph_integer_t i;++    if (start < 0 || start >= vc) {+        IGRAPH_ERROR("Invalid start vertex", IGRAPH_EINVAL);+    }+    if (steps < 0) {+        IGRAPH_ERROR("Invalid number of steps", IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_lazy_adjlist_init(graph, &adj, mode,+                                          IGRAPH_DONT_SIMPLIFY));+    IGRAPH_FINALLY(igraph_lazy_adjlist_destroy, &adj);++    IGRAPH_CHECK(igraph_vector_resize(walk, steps));++    RNG_BEGIN();++    VECTOR(*walk)[0] = start;+    for (i = 1; i < steps; i++) {+        igraph_vector_t *neis;+        igraph_integer_t nn;+        neis = igraph_lazy_adjlist_get(&adj, start);+        nn = igraph_vector_size(neis);++        if (IGRAPH_UNLIKELY(nn == 0)) {+            igraph_vector_resize(walk, i);+            if (stuck == IGRAPH_RANDOM_WALK_STUCK_RETURN) {+                break;+            } else {+                IGRAPH_ERROR("Random walk got stuck", IGRAPH_ERWSTUCK);+            }+        }+        start = VECTOR(*walk)[i] = VECTOR(*neis)[ RNG_INTEGER(0, nn - 1) ];+    }++    RNG_END();++    igraph_lazy_adjlist_destroy(&adj);+    IGRAPH_FINALLY_CLEAN(1);++    return 0;+}+++/* Used as item destructor for 'cdfs' in igraph_random_edge_walk(). */+static void vec_destr(igraph_vector_t *vec) {+    if (vec != NULL) {+        igraph_vector_destroy(vec);+    }+}+++/**+ * \function igraph_random_edge_walk+ * \brief Perform a random walk on a graph and return the traversed edges+ *+ * Performs a random walk with a given length on a graph, from the given+ * start vertex. Edge directions are (potentially) considered, depending on+ * the \p mode argument.+ *+ * \param graph The input graph, it can be directed or undirected.+ *   Multiple edges are respected, so are loop edges.+ * \param weights A vector of non-negative edge weights.+ *   It is assumed that at least one strictly positive weight is found among the+ *   outgoing edges of each vertex.  If it is a NULL pointer, all edges are considered+ *   to have equal weight.+ * \param edgewalk An initialized vector; the indices of traversed edges are stored here.+ *   It will be resized as needed.+ * \param start The start vertex for the walk.+ * \param steps The number of steps to take. If the random walk gets+ *   stuck, then the \p stuck argument specifies what happens.+ * \param mode How to walk along the edges in direted graphs.+ *   \c IGRAPH_OUT means following edge directions, \c IGRAPH_IN means+ *   going opposite the edge directions, \c IGRAPH_ALL means ignoring+ *   edge directions. This argument is ignored for undirected graphs.+ * \param stuck What to do if the random walk gets stuck.+ *   \c IGRAPH_RANDOM_WALK_STUCK_RETURN means that the function returns+ *   with a shorter walk; \c IGRAPH_RANDOM_WALK_STUCK_ERROR means+ *   that an error is reported. In both cases, \p edgewalk is truncated+ *   to contain the actual interrupted walk.+ *+ * \return Error code.+ *+ */+int igraph_random_edge_walk(const igraph_t *graph,+                            const igraph_vector_t *weights,+                            igraph_vector_t *edgewalk,+                            igraph_integer_t start, igraph_neimode_t mode,+                            igraph_integer_t steps,+                            igraph_random_walk_stuck_t stuck) {+    igraph_integer_t vc = igraph_vcount(graph);+    igraph_integer_t ec = igraph_ecount(graph);+    igraph_integer_t i;+    igraph_inclist_t il;+    igraph_vector_t weight_temp;+    igraph_vector_ptr_t cdfs; /* cumulative distribution vectors for each node, used for weighted choice */++    /* the fourth igraph_neimode_t value, IGRAPH_TOTAL, is disallowed */+    if (! (mode == IGRAPH_ALL || mode == IGRAPH_IN || mode == IGRAPH_OUT)) {+        IGRAPH_ERROR("Invalid mode parameter", IGRAPH_EINVMODE);+    }++    /* ref switch statement at end of main loop */+    if (! igraph_is_directed(graph)) {+        mode = IGRAPH_ALL;+    }++    if (start < 0 || start >= vc) {+        IGRAPH_ERROR("Invalid start vertex", IGRAPH_EINVAL);+    }++    if (steps < 0) {+        IGRAPH_ERROR("Invalid number of steps", IGRAPH_EINVAL);+    }++    if (weights) {+        if (igraph_vector_size(weights) != ec) {+            IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+        }+        if (igraph_vector_min(weights) < 0) {+            IGRAPH_ERROR("Weights must be non-negative", IGRAPH_EINVAL);+        }+    }++    IGRAPH_CHECK(igraph_vector_resize(edgewalk, steps));++    IGRAPH_CHECK(igraph_inclist_init(graph, &il, mode));+    IGRAPH_FINALLY(igraph_inclist_destroy, &il);++    IGRAPH_VECTOR_INIT_FINALLY(&weight_temp, 0);++    /* cdf vectors will be computed lazily */+    IGRAPH_CHECK(igraph_vector_ptr_init(&cdfs, vc));+    IGRAPH_FINALLY(igraph_vector_ptr_destroy_all, &cdfs);+    IGRAPH_VECTOR_PTR_SET_ITEM_DESTRUCTOR(&cdfs, vec_destr);+    for (i = 0; i < vc; ++i) {+        VECTOR(cdfs)[i] = NULL;+    }++    RNG_BEGIN();++    for (i = 0; i < steps; ++i) {+        long degree, edge, idx;+        igraph_vector_int_t *edges = igraph_inclist_get(&il, start);++        degree = igraph_vector_int_size(edges);++        /* are we stuck? */+        if (IGRAPH_UNLIKELY(degree == 0)) {+            igraph_vector_resize(edgewalk, i); /* can't fail since size is reduced, skip IGRAPH_CHECK */+            if (stuck == IGRAPH_RANDOM_WALK_STUCK_RETURN) {+                break;+            } else {+                IGRAPH_ERROR("Random walk got stuck", IGRAPH_ERWSTUCK);+            }+        }++        if (weights) { /* weighted: choose an out-edge with probability proportional to its weight */+            igraph_real_t r;+            igraph_vector_t **cd = (igraph_vector_t **) & (VECTOR(cdfs)[start]);++            /* compute out-edge cdf for this node if not already done */+            if (IGRAPH_UNLIKELY(! *cd)) {+                long j;++                *cd = igraph_malloc(sizeof(igraph_vector_t));+                if (*cd == NULL) {+                    IGRAPH_ERROR("random edge walk failed", IGRAPH_ENOMEM);+                }+                IGRAPH_CHECK(igraph_vector_init(*cd, degree));++                IGRAPH_CHECK(igraph_vector_resize(&weight_temp, degree));+                for (j = 0; j < degree; ++j) {+                    VECTOR(weight_temp)[j] = VECTOR(*weights)[ VECTOR(*edges)[j] ];+                }++                IGRAPH_CHECK(igraph_vector_cumsum(*cd, &weight_temp));+            }++            r = RNG_UNIF(0, VECTOR( **cd )[degree - 1]);+            igraph_vector_binsearch(*cd, r, &idx);+        } else { /* unweighted: choose an out-edge at random */+            idx = RNG_INTEGER(0, degree - 1);+        }++        edge = VECTOR(*edges)[idx];+        VECTOR(*edgewalk)[i] = edge;++        /* travel along edge in a direction specified by 'mode' */+        /* note: 'mode' is always set to IGRAPH_ALL for undirected graphs */+        switch (mode) {+        case IGRAPH_OUT:+            start = IGRAPH_TO(graph, edge);+            break;+        case IGRAPH_IN:+            start = IGRAPH_FROM(graph, edge);+            break;+        case IGRAPH_ALL:+            start = IGRAPH_OTHER(graph, edge, start);+            break;+        }++        IGRAPH_ALLOW_INTERRUPTION();+    }++    RNG_END();++    igraph_vector_ptr_destroy_all(&cdfs);+    igraph_vector_destroy(&weight_temp);+    igraph_inclist_destroy(&il);+    IGRAPH_FINALLY_CLEAN(3);++    return IGRAPH_SUCCESS;+}
+ igraph/src/rdfmt.c view
@@ -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
+ igraph/src/reorder.c view
@@ -0,0 +1,425 @@++/*+ * This file contains the vertex reordering routines.+ *+ * Copyright (C) 2002 Sampo Niskanen, Patric Östergård.+ * Licensed under the GNU GPL, read the file LICENSE for details.+ */++#include "reorder.h"++#include <stdlib.h>++#include <limits.h>++#include <igraph_random.h>+++/*+ * reorder_set()+ *+ * Reorders the set s with a function  i -> order[i].+ *+ * Note: Assumes that order is the same size as SET_MAX_SIZE(s).+ */+void reorder_set(set_t s,int *order) {+        set_t tmp;+        int i,j;+        setelement e;++        ASSERT(reorder_is_bijection(order,SET_MAX_SIZE(s)));++        tmp=set_new(SET_MAX_SIZE(s));++        for (i=0; i<(SET_MAX_SIZE(s)/ELEMENTSIZE); i++) {+                e=s[i];+                if (e==0)+                        continue;+                for (j=0; j<ELEMENTSIZE; j++) {+                        if (e&1) {+                                SET_ADD_ELEMENT(tmp,order[i*ELEMENTSIZE+j]);+                        }+                        e = e>>1;+                }+        }+        if (SET_MAX_SIZE(s)%ELEMENTSIZE) {+                e=s[i];+                for (j=0; j<(SET_MAX_SIZE(s)%ELEMENTSIZE); j++) {+                        if (e&1) {+                                SET_ADD_ELEMENT(tmp,order[i*ELEMENTSIZE+j]);+                        }+                        e = e>>1;+                }+        }+        set_copy(s,tmp);+        set_free(tmp);+        return;+}+++/*+ * reorder_graph()+ *+ * Reorders the vertices in the graph with function  i -> order[i].+ *+ * Note: Assumes that order is of size g->n.+ */+void reorder_graph(graph_t *g, int *order) {+        int i;+        set_t *tmp_e;+        int *tmp_w;++        ASSERT(reorder_is_bijection(order,g->n));++        tmp_e=malloc(g->n * sizeof(set_t));+        tmp_w=malloc(g->n * sizeof(int));+        for (i=0; i<g->n; i++) {+                reorder_set(g->edges[i],order);+                tmp_e[order[i]]=g->edges[i];+                tmp_w[order[i]]=g->weights[i];+        }+        for (i=0; i<g->n; i++) {+                g->edges[i]=tmp_e[i];+                g->weights[i]=tmp_w[i];+        }+        free(tmp_e);+        free(tmp_w);+        return;+}++++/*+ * reorder_duplicate()+ *+ * Returns a newly allocated duplicate of the given ordering.+ */+int *reorder_duplicate(int *order,int n) {+	int *new;++	new=malloc(n*sizeof(int));+	memcpy(new,order,n*sizeof(int));+	return new;+}++/*+ * reorder_invert()+ *+ * Inverts the given ordering so that new[old[i]]==i.+ *+ * Note: Asserts that order is a bijection.+ */+void reorder_invert(int *order,int n) {+	int *new;+	int i;++	ASSERT(reorder_is_bijection(order,n));++	new=malloc(n*sizeof(int));+	for (i=0; i<n; i++)+		new[order[i]]=i;+	for (i=0; i<n; i++)+		order[i]=new[i];+	free(new);+	return;+}++/*+ * reorder_reverse()+ *+ * Reverses the given ordering so that  new[i] == n-1 - old[i].+ */+void reorder_reverse(int *order,int n) {+	int i;++	for (i=0; i<n; i++)+		order[i] = n-1 - order[i];+	return;+}++/*+ * reorder_is_bijection+ *+ * Checks that an ordering is a bijection {0,...,n-1} -> {0,...,n-1}.+ *+ * Returns TRUE if it is a bijection, FALSE otherwise.+ */+boolean reorder_is_bijection(int *order,int n) {+	boolean *used;+	int i;++	used=calloc(n,sizeof(boolean));+	for (i=0; i<n; i++) {+		if (order[i]<0 || order[i]>=n) {+			free(used);+			return FALSE;+		}+		if (used[order[i]]) {+			free(used);+			return FALSE;+		}+		used[order[i]]=TRUE;+	}+	for (i=0; i<n; i++) {+		if (!used[i]) {+			free(used);+			return FALSE;+		}+	}+	free(used);+	return TRUE;+}++/*+ * reorder_ident()+ *+ * Returns a newly allocated identity ordering of size n, ie. order[i]==i.+ */+int *reorder_ident(int n) {+	int i;+	int *order;++	order=malloc(n*sizeof(int));+	for (i=0; i<n; i++)+		order[i]=i;+	return order;+}++++/*** Reordering functions for use in clique_options ***/++/*+ * reorder_by_ident()+ *+ * Returns an identity ordering.+ */+int *reorder_by_ident(graph_t *g,boolean weighted) {+	return reorder_ident(g->n);+}++/*+ * reorder_by_reverse()+ *+ * Returns a reverse identity ordering.+ */+int *reorder_by_reverse(graph_t *g,boolean weighted) {+	int i;+	int *order;++	order=malloc(g->n * sizeof(int));+	for (i=0; i < g->n; i++)+		order[i]=g->n-i-1;+	return order;+}++/*+ * reorder_by_greedy_coloring()+ *+ * Equivalent to reorder_by_weighted_greedy_coloring or+ * reorder_by_unweighted_greedy_coloring according to the value of weighted.+ */+int *reorder_by_greedy_coloring(graph_t *g,boolean weighted) {+	if (weighted)+		return reorder_by_weighted_greedy_coloring(g,weighted);+	else+		return reorder_by_unweighted_greedy_coloring(g,weighted);+}+++/*+ * reorder_by_unweighted_greedy_coloring()+ *+ * Returns an ordering for the graph g by coloring the clique one+ * color at a time, always adding the vertex of largest degree within+ * the uncolored graph, and numbering these vertices 0, 1, ...+ *+ * Experimentally efficient for use with unweighted graphs.+ */+int *reorder_by_unweighted_greedy_coloring(graph_t *g,boolean weighted) {+	int i,j,v;+	boolean *tmp_used;+	int *degree;   /* -1 for used vertices */+	int *order;+	int maxdegree,maxvertex=0;+	boolean samecolor;++	tmp_used=calloc(g->n,sizeof(boolean));+	degree=calloc(g->n,sizeof(int));+	order=calloc(g->n,sizeof(int));++	for (i=0; i < g->n; i++) {+		for (j=0; j < g->n; j++) {+			ASSERT(!((i==j) && GRAPH_IS_EDGE(g,i,j)));+			if (GRAPH_IS_EDGE(g,i,j))+				degree[i]++;+		}+	}++	v=0;+	while (v < g->n) {+		/* Reset tmp_used. */+		memset(tmp_used,0,g->n * sizeof(boolean));++		do {+			/* Find vertex to be colored. */+			maxdegree=0;+			samecolor=FALSE;+			for (i=0; i < g->n; i++) {+				if (!tmp_used[i] && degree[i] >= maxdegree) {+					maxvertex=i;+					maxdegree=degree[i];+					samecolor=TRUE;+				}+			}+			if (samecolor) {+				order[v]=maxvertex;+				degree[maxvertex]=-1;+				v++;++				/* Mark neighbors not to color with same+				 * color and update neighbor degrees. */+				for (i=0; i < g->n; i++) {+					if (GRAPH_IS_EDGE(g,maxvertex,i)) {+						tmp_used[i]=TRUE;+						degree[i]--;+					}+				}+			}+		} while (samecolor);+	}++	free(tmp_used);+	free(degree);+	return order;+}++/*+ * reorder_by_weighted_greedy_coloring()+ *+ * Returns an ordering for the graph g by coloring the clique one+ * color at a time, always adding the vertex that (in order of importance):+ *  1. has the minimum weight in the remaining graph+ *  2. has the largest sum of weights surrounding the vertex+ *+ * Experimentally efficient for use with weighted graphs.+ */+int *reorder_by_weighted_greedy_coloring(graph_t *g, boolean weighted) {+	int i,j,p=0;+	int cnt;+	int *nwt;    /* Sum of surrounding vertices' weights */+	int min_wt,max_nwt;+	boolean *used;+	int *order;+	+	nwt=malloc(g->n * sizeof(int));+	order=malloc(g->n * sizeof(int));+	used=calloc(g->n,sizeof(boolean));+	+	for (i=0; i < g->n; i++) {+		nwt[i]=0;+		for (j=0; j < g->n; j++)+			if (GRAPH_IS_EDGE(g, i, j))+				nwt[i] += g->weights[j];+	}++	for (cnt=0; cnt < g->n; cnt++) {+		min_wt=INT_MAX;+		max_nwt=-1;+		for (i=g->n-1; i>=0; i--)+			if ((!used[i]) && (g->weights[i] < min_wt))+				min_wt=g->weights[i];+		for (i=g->n-1; i>=0; i--) {+			if (used[i] || (g->weights[i] > min_wt))+				continue;+			if (nwt[i] > max_nwt) {+				max_nwt=nwt[i];+				p=i;+			}+		}+		order[cnt]=p;+		used[p]=TRUE;+		for (j=0; j < g->n; j++)+			if ((!used[j]) && (GRAPH_IS_EDGE(g, p, j)))+				nwt[j] -= g->weights[p];+	}++	free(nwt);+	free(used);++	ASSERT(reorder_is_bijection(order,g->n));++	return order;+}++/*+ * reorder_by_degree()+ *+ * Returns a reordering of the graph g so that the vertices with largest+ * degrees (most neighbors) are first.+ */+int *reorder_by_degree(graph_t *g, boolean weighted) {+	int i,j,v;+	int *degree;+	int *order;+	int maxdegree,maxvertex=0;++	degree=calloc(g->n,sizeof(int));+	order=calloc(g->n,sizeof(int));++	for (i=0; i < g->n; i++) {+		for (j=0; j < g->n; j++) {+			ASSERT(!((i==j) && GRAPH_IS_EDGE(g,i,j)));+			if (GRAPH_IS_EDGE(g,i,j))+				degree[i]++;+		}+	}++	for (v=0; v < g->n; v++) {+		maxdegree=0;+		for (i=0; i < g->n; i++) {+			if (degree[i] >= maxdegree) {+				maxvertex=i;+				maxdegree=degree[i];+			}+		}+		order[v]=maxvertex;+		degree[maxvertex]=-1;  /* used */+/*** Max. degree withing unselected graph:+		for (i=0; i < g->n; i++) {+			if (GRAPH_IS_EDGE(g,maxvertex,i))+				degree[i]--;+		}+***/+	}++	free(degree);+	return order;+}++/*+ * reorder_by_random()+ *+ * Returns a random reordering for graph g.+ * Note: Used the functions rand() and srand() to generate the random+ *       numbers.  srand() is re-initialized every time reorder_by_random()+ *       is called using the system time.+ */+int *reorder_by_random(graph_t *g, boolean weighted) {+	int i,r;+	int *new;+	boolean *used;++	new=calloc(g->n, sizeof(int));+	used=calloc(g->n, sizeof(boolean));+	for (i=0; i < g->n; i++) {+		do {+            r = igraph_rng_get_integer(igraph_rng_default(), 0, g->n - 1);+		} while (used[r]);+		new[i]=r;+		used[r]=TRUE;+	}+	free(used);+	return new;+}+
+ igraph/src/rewind.c view
@@ -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
+ igraph/src/rsfe.c view
@@ -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
+ igraph/src/rsli.c view
@@ -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
+ igraph/src/rsne.c view
@@ -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
+ igraph/src/s_cat.c view
@@ -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
+ igraph/src/s_cmp.c view
@@ -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
+ igraph/src/s_copy.c view
@@ -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
+ igraph/src/s_paus.c view
@@ -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
+ igraph/src/s_rnge.c view
@@ -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
+ igraph/src/s_stop.c view
@@ -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
+ igraph/src/sbm.c view
@@ -0,0 +1,607 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph R library.+   Copyright (C) 2003-2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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"++#include <float.h>      /* for DBL_EPSILON */+#include <math.h>       /* for sqrt */++/**+ * \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., &amp; 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++) {+        double 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++) {+            double 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;+}++/**+ * \function igraph_hsbm_game+ * Hierarchical stochastic block model+ *+ * The function generates a random graph according to the hierarchical+ * stochastic block model.+ *+ * \param graph The generated graph is stored here.+ * \param n The number of vertices in the graph.+ * \param m The number of vertices per block. n/m must be integer.+ * \param rho The fraction of vertices per cluster,+ *        within a block. Must sum up to 1, and rho * m must be integer+ *        for all elements of rho.+ * \param C A square, symmetric numeric matrix, the Bernoulli rates for+ *        the clusters within a block. Its size must mach the size of the+ *        \code{rho} vector.+ * \param p The Bernoulli rate of connections between+ *        vertices in different blocks.+ * \return Error code.+ *+ * \sa \ref igraph_sbm_game() for the classic stochastic block model,+ * \ref igraph_hsbm_list_game() for a more general version.+ */++int igraph_hsbm_game(igraph_t *graph, igraph_integer_t n,+                     igraph_integer_t m, const igraph_vector_t *rho,+                     const igraph_matrix_t *C, igraph_real_t p) {++    int b, i, k = igraph_vector_size(rho);+    igraph_vector_t csizes;+    igraph_real_t sq_dbl_epsilon = sqrt(DBL_EPSILON);+    int no_blocks = n / m;+    igraph_vector_t edges;+    int offset = 0;++    if (n < 1) {+        IGRAPH_ERROR("`n' must be positive for HSBM", IGRAPH_EINVAL);+    }+    if (m < 1) {+        IGRAPH_ERROR("`m' must be positive for HSBM", IGRAPH_EINVAL);+    }+    if ((long) n  % (long) m) {+        IGRAPH_ERROR("`n' must be a multiple of `m' for HSBM", IGRAPH_EINVAL);+    }+    if (!igraph_vector_isininterval(rho, 0, 1)) {+        IGRAPH_ERROR("`rho' must be between zero and one for HSBM",+                     IGRAPH_EINVAL);+    }+    if (igraph_matrix_min(C) < 0 || igraph_matrix_max(C) > 1) {+        IGRAPH_ERROR("`C' must be between zero and one for HSBM", IGRAPH_EINVAL);+    }+    if (fabs(igraph_vector_sum(rho) - 1.0) > sq_dbl_epsilon) {+        IGRAPH_ERROR("`rho' must sum up to 1 for HSBM", IGRAPH_EINVAL);+    }+    if (igraph_matrix_nrow(C) != k || igraph_matrix_ncol(C) != k) {+        IGRAPH_ERROR("`C' dimensions must match `rho' dimensions in HSBM",+                     IGRAPH_EINVAL);+    }+    if (!igraph_matrix_is_symmetric(C)) {+        IGRAPH_ERROR("`C' must be a symmetric matrix", IGRAPH_EINVAL);+    }+    if (p < 0 || p > 1) {+        IGRAPH_ERROR("`p' must be a probability for HSBM", IGRAPH_EINVAL);+    }+    for (i = 0; i < k; i++) {+        igraph_real_t s = VECTOR(*rho)[i] * m;+        if (fabs(round(s) - s) > sq_dbl_epsilon) {+            IGRAPH_ERROR("`rho' * `m' is not integer in HSBM", IGRAPH_EINVAL);+        }+    }++    IGRAPH_VECTOR_INIT_FINALLY(&csizes, k);+    for (i = 0; i < k; i++) {+        VECTOR(csizes)[i] = round(VECTOR(*rho)[i] * m);+    }++    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);++    RNG_BEGIN();++    /* Block models first */++    for (b = 0; b < no_blocks; b++) {+        int from, to, fromoff = 0;++        for (from = 0; from < k; from++) {+            int fromsize = VECTOR(csizes)[from];+            int i, tooff = 0;+            for (i = 0; i < from; i++) {+                tooff += VECTOR(csizes)[i];+            }+            for (to = from; to < k; to++) {+                int tosize = VECTOR(csizes)[to];+                igraph_real_t prob = MATRIX(*C, from, to);+                igraph_real_t maxedges;+                igraph_real_t last = RNG_GEOM(prob);+                if (from != to) {+                    maxedges = fromsize * tosize;+                    while (last < maxedges) {+                        int vto = floor(last / fromsize);+                        int vfrom = last - (igraph_real_t)vto * fromsize;+                        igraph_vector_push_back(&edges, offset + fromoff + vfrom);+                        igraph_vector_push_back(&edges, offset + tooff + vto);+                        last += RNG_GEOM(prob);+                        last += 1;+                    }+                } else { /* from==to */+                    maxedges = fromsize * (fromsize - 1) / 2.0;+                    while (last < maxedges) {+                        int vto = floor((sqrt(8 * last + 1) + 1) / 2);+                        int vfrom = last - (((igraph_real_t)vto) * (vto - 1)) / 2;+                        igraph_vector_push_back(&edges, offset + fromoff + vfrom);+                        igraph_vector_push_back(&edges, offset + tooff + vto);+                        last += RNG_GEOM(prob);+                        last += 1;+                    }+                }++                tooff += tosize;+            }+            fromoff += fromsize;+        }++        offset += m;+    }++    /* And now the rest, if not a special case */++    if (p == 1) {+        int fromoff = 0, tooff = m;+        for (b = 0; b < no_blocks; b++) {+            igraph_real_t fromsize = m;+            igraph_real_t tosize = n - tooff;+            int from, to;+            for (from = 0; from < fromsize; from++) {+                for (to = 0; to < tosize; to++) {+                    igraph_vector_push_back(&edges, fromoff + from);+                    igraph_vector_push_back(&edges, tooff + to);+                }+            }+            fromoff += m;+            tooff += m;+        }+    } else if (p > 0) {+        int fromoff = 0, tooff = m;+        for (b = 0; b < no_blocks; b++) {+            igraph_real_t fromsize = m;+            igraph_real_t tosize = n - tooff;+            igraph_real_t maxedges = fromsize * tosize;+            igraph_real_t last = RNG_GEOM(p);+            while (last < maxedges) {+                int vto = floor(last / fromsize);+                int vfrom = last - (igraph_real_t) vto * fromsize;+                igraph_vector_push_back(&edges, fromoff + vfrom);+                igraph_vector_push_back(&edges, tooff + vto);+                last += RNG_GEOM(p);+                last += 1;+            }++            fromoff += m;+            tooff += m;+        }+    }++    RNG_END();++    igraph_create(graph, &edges, n, /*directed=*/ 0);++    igraph_vector_destroy(&edges);+    igraph_vector_destroy(&csizes);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}++/**+ * \function igraph_hsbm_list_game+ * Hierarchical stochastic block model, more general version+ *+ * The function generates a random graph according to the hierarchical+ * stochastic block model.+ *+ * \param graph The generated graph is stored here.+ * \param n The number of vertices in the graph.+ * \param mlist An integer vector of block sizes.+ * \param rholist A list of rho vectors (\c igraph_vector_t objects), one+ *        for each block.+ * \param Clist A list of square matrices (\c igraph_matrix_t objects),+ *        one for each block, giving the Bernoulli rates of connections+ *        within the block.+ * \param p The Bernoulli rate of connections between+ *        vertices in different blocks.+ * \return Error code.+ *+ * \sa \ref igraph_sbm_game() for the classic stochastic block model,+ * \ref igraph_hsbm_game() for a simpler general version.+ */++int igraph_hsbm_list_game(igraph_t *graph, igraph_integer_t n,+                          const igraph_vector_int_t *mlist,+                          const igraph_vector_ptr_t *rholist,+                          const igraph_vector_ptr_t *Clist,+                          igraph_real_t p) {++    int i, no_blocks = igraph_vector_ptr_size(rholist);+    igraph_real_t sq_dbl_epsilon = sqrt(DBL_EPSILON);+    igraph_vector_t csizes, edges;+    int b, offset = 0;++    if (n < 1) {+        IGRAPH_ERROR("`n' must be positive for HSBM", IGRAPH_EINVAL);+    }+    if (no_blocks == 0) {+        IGRAPH_ERROR("`rholist' empty for HSBM", IGRAPH_EINVAL);+    }+    if (igraph_vector_ptr_size(Clist) != no_blocks &&+        igraph_vector_int_size(mlist) != no_blocks) {+        IGRAPH_ERROR("`rholist' must have same length as `Clist' and `m' "+                     "for HSBM", IGRAPH_EINVAL);+    }+    if (p < 0 || p > 1) {+        IGRAPH_ERROR("`p' must be a probability for HSBM", IGRAPH_EINVAL);+    }+    /* Checks for m's */+    if (igraph_vector_int_sum(mlist) != n) {+        IGRAPH_ERROR("`m' must sum up to `n' for HSBM", IGRAPH_EINVAL);+    }+    if (igraph_vector_int_min(mlist) < 1) {+        IGRAPH_ERROR("`m' must be positive for HSBM", IGRAPH_EINVAL);+    }+    /* Checks for the rhos */+    for (i = 0; i < no_blocks; i++) {+        const igraph_vector_t *rho = VECTOR(*rholist)[i];+        if (!igraph_vector_isininterval(rho, 0, 1)) {+            IGRAPH_ERROR("`rho' must be between zero and one for HSBM",+                         IGRAPH_EINVAL);+        }+        if (fabs(igraph_vector_sum(rho) - 1.0) > sq_dbl_epsilon) {+            IGRAPH_ERROR("`rho' must sum up to 1 for HSBM", IGRAPH_EINVAL);+        }+    }+    /* Checks for the Cs */+    for (i = 0; i < no_blocks; i++) {+        const igraph_matrix_t *C = VECTOR(*Clist)[i];+        if (igraph_matrix_min(C) < 0 || igraph_matrix_max(C) > 1) {+            IGRAPH_ERROR("`C' must be between zero and one for HSBM",+                         IGRAPH_EINVAL);+        }+        if (!igraph_matrix_is_symmetric(C)) {+            IGRAPH_ERROR("`C' must be a symmetric matrix", IGRAPH_EINVAL);+        }+    }+    /* Check that C and rho sizes match */+    for (i = 0; i < no_blocks; i++) {+        const igraph_vector_t *rho = VECTOR(*rholist)[i];+        const igraph_matrix_t *C = VECTOR(*Clist)[i];+        int k = igraph_vector_size(rho);+        if (igraph_matrix_nrow(C) != k || igraph_matrix_ncol(C) != k) {+            IGRAPH_ERROR("`C' dimensions must match `rho' dimensions in HSBM",+                         IGRAPH_EINVAL);+        }+    }+    /* Check that rho * m is integer */+    for (i = 0; i < no_blocks; i++) {+        const igraph_vector_t *rho = VECTOR(*rholist)[i];+        igraph_real_t m = VECTOR(*mlist)[i];+        int j, k = igraph_vector_size(rho);+        for (j = 0; j < k; j++) {+            igraph_real_t s = VECTOR(*rho)[j] * m;+            if (fabs(round(s) - s) > sq_dbl_epsilon) {+                IGRAPH_ERROR("`rho' * `m' is not integer in HSBM", IGRAPH_EINVAL);+            }+        }+    }++    IGRAPH_VECTOR_INIT_FINALLY(&csizes, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);++    RNG_BEGIN();++    /* Block models first */++    for (b = 0; b < no_blocks; b++) {+        int from, to, fromoff = 0;+        const igraph_vector_t *rho = VECTOR(*rholist)[b];+        const igraph_matrix_t *C = VECTOR(*Clist)[b];+        igraph_real_t m = VECTOR(*mlist)[b];+        int k = igraph_vector_size(rho);++        igraph_vector_resize(&csizes, k);+        for (i = 0; i < k; i++) {+            VECTOR(csizes)[i] = round(VECTOR(*rho)[i] * m);+        }++        for (from = 0; from < k; from++) {+            int fromsize = VECTOR(csizes)[from];+            int i, tooff = 0;+            for (i = 0; i < from; i++) {+                tooff += VECTOR(csizes)[i];+            }+            for (to = from; to < k; to++) {+                int tosize = VECTOR(csizes)[to];+                igraph_real_t prob = MATRIX(*C, from, to);+                igraph_real_t maxedges;+                igraph_real_t last = RNG_GEOM(prob);+                if (from != to) {+                    maxedges = fromsize * tosize;+                    while (last < maxedges) {+                        int vto = floor(last / fromsize);+                        int vfrom = last - (igraph_real_t)vto * fromsize;+                        igraph_vector_push_back(&edges, offset + fromoff + vfrom);+                        igraph_vector_push_back(&edges, offset + tooff + vto);+                        last += RNG_GEOM(prob);+                        last += 1;+                    }+                } else { /* from==to */+                    maxedges = fromsize * (fromsize - 1) / 2.0;+                    while (last < maxedges) {+                        int vto = floor((sqrt(8 * last + 1) + 1) / 2);+                        int vfrom = last - (((igraph_real_t)vto) * (vto - 1)) / 2;+                        igraph_vector_push_back(&edges, offset + fromoff + vfrom);+                        igraph_vector_push_back(&edges, offset + tooff + vto);+                        last += RNG_GEOM(prob);+                        last += 1;+                    }+                }++                tooff += tosize;+            }+            fromoff += fromsize;+        }++        offset += m;+    }++    /* And now the rest, if not a special case */++    if (p == 1) {+        int fromoff = 0, tooff = VECTOR(*mlist)[0];+        for (b = 0; b < no_blocks; b++) {+            igraph_real_t fromsize = VECTOR(*mlist)[b];+            igraph_real_t tosize = n - tooff;+            int from, to;+            for (from = 0; from < fromsize; from++) {+                for (to = 0; to < tosize; to++) {+                    igraph_vector_push_back(&edges, fromoff + from);+                    igraph_vector_push_back(&edges, tooff + to);+                }+            }+            fromoff += fromsize;+            if (b + 1 < no_blocks) {+                tooff += VECTOR(*mlist)[b + 1];+            }+        }+    } else if (p > 0) {+        int fromoff = 0, tooff = VECTOR(*mlist)[0];+        for (b = 0; b < no_blocks; b++) {+            igraph_real_t fromsize = VECTOR(*mlist)[b];+            igraph_real_t tosize = n - tooff;+            igraph_real_t maxedges = fromsize * tosize;+            igraph_real_t last = RNG_GEOM(p);+            while (last < maxedges) {+                int vto = floor(last / fromsize);+                int vfrom = last - (igraph_real_t) vto * fromsize;+                igraph_vector_push_back(&edges, fromoff + vfrom);+                igraph_vector_push_back(&edges, tooff + vto);+                last += RNG_GEOM(p);+                last += 1;+            }++            fromoff += fromsize;+            if (b + 1 < no_blocks) {+                tooff += VECTOR(*mlist)[b + 1];+            }+        }+    }++    RNG_END();++    igraph_create(graph, &edges, n, /*directed=*/ 0);++    igraph_vector_destroy(&edges);+    igraph_vector_destroy(&csizes);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}
+ igraph/src/scan.c view
@@ -0,0 +1,880 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2013  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along with this program; if not, write to the Free Software+   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA+   02110-1301 USA++*/++#include "igraph_scan.h"+#include "igraph_interface.h"+#include "igraph_adjlist.h"+#include "igraph_memory.h"+#include "igraph_interrupt_internal.h"+#include "igraph_arpack.h"+#include "igraph_eigen.h"+#include "igraph_centrality.h"+#include "igraph_operators.h"+#include "igraph_dqueue.h"+#include "igraph_stack.h"++/**+ * \section about_local_scan+ *+ * <para>+ * The scan statistic is a summary of the locality statistics that is computed+ * from the local neighborhood of each vertex. For details, see+ * Priebe, C. E., Conroy, J. M., Marchette, D. J., Park, Y. (2005).+ * Scan Statistics on Enron Graphs. Computational and Mathematical Organization Theory.+ * </para>+ */++/**+ * \function igraph_local_scan_0+ * Local scan-statistics, k=0+ *+ * K=0 scan-statistics is arbitrarily defined as the vertex degree for+ * unweighted, and the vertex strength for weighted graphs. See \ref+ * igraph_degree() and \ref igraph_strength().+ *+ * \param graph The input graph+ * \param res An initialized vector, the results are stored here.+ * \param weights Weight vector for weighted graphs, null pointer for+ *        unweighted graphs.+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.+ * \return Error code.+ *+ */++int igraph_local_scan_0(const igraph_t *graph, igraph_vector_t *res,+                        const igraph_vector_t *weights,+                        igraph_neimode_t mode) {+    if (weights) {+        igraph_strength(graph, res, igraph_vss_all(), mode, /*loops=*/ 1,+                        weights);+    } else {+        igraph_degree(graph, res, igraph_vss_all(), mode, /*loops=*/ 1);+    }+    return 0;+}++/* From triangles.c */++int igraph_i_trans4_al_simplify(igraph_adjlist_t *al,+                                const igraph_vector_int_t *rank);++/* This removes loop, multiple edges and edges that point+   "backwards" according to the rank vector. It works on+   edge lists */++int igraph_i_trans4_il_simplify(const igraph_t *graph, igraph_inclist_t *il,+                                const igraph_vector_int_t *rank) {++    long int i;+    long int n = il->length;+    igraph_vector_int_t mark;+    igraph_vector_int_init(&mark, n);+    IGRAPH_FINALLY(igraph_vector_int_destroy, &mark);++    for (i = 0; i < n; i++) {+        igraph_vector_int_t *v = &il->incs[i];+        int j, l = igraph_vector_int_size(v);+        int irank = VECTOR(*rank)[i];+        VECTOR(mark)[i] = i + 1;+        for (j = 0; j < l; /* nothing */) {+            long int edge = (long int) VECTOR(*v)[j];+            long int e = IGRAPH_OTHER(graph, edge, i);+            if (VECTOR(*rank)[e] > irank && VECTOR(mark)[e] != i + 1) {+                VECTOR(mark)[e] = i + 1;+                j++;+            } else {+                VECTOR(*v)[j] = igraph_vector_int_tail(v);+                igraph_vector_int_pop_back(v);+                l--;+            }+        }+    }++    igraph_vector_int_destroy(&mark);+    IGRAPH_FINALLY_CLEAN(1);+    return 0;++}++/* This one handles both weighted and unweighted cases */++int igraph_i_local_scan_1_directed(const igraph_t *graph,+                                   igraph_vector_t *res,+                                   const igraph_vector_t *weights,+                                   igraph_neimode_t mode) {++    int no_of_nodes = igraph_vcount(graph);+    igraph_inclist_t incs;+    int i, node;++    igraph_vector_int_t neis;++    IGRAPH_CHECK(igraph_inclist_init(graph, &incs, mode));+    IGRAPH_FINALLY(igraph_inclist_destroy, &incs);++    igraph_vector_int_init(&neis, no_of_nodes);+    IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);++    igraph_vector_resize(res, no_of_nodes);+    igraph_vector_null(res);++    for (node = 0; node < no_of_nodes; node++) {+        igraph_vector_int_t *edges1 = igraph_inclist_get(&incs, node);+        int edgeslen1 = igraph_vector_int_size(edges1);++        IGRAPH_ALLOW_INTERRUPTION();++        /* Mark neighbors and self*/+        VECTOR(neis)[node] = node + 1;+        for (i = 0; i < edgeslen1; i++) {+            int e = VECTOR(*edges1)[i];+            int nei = IGRAPH_OTHER(graph, e, node);+            igraph_real_t w = weights ? VECTOR(*weights)[e] : 1;+            VECTOR(neis)[nei] = node + 1;+            VECTOR(*res)[node] += w;+        }++        /* Crawl neighbors */+        for (i = 0; i < edgeslen1; i++) {+            int e2 = VECTOR(*edges1)[i];+            int nei = IGRAPH_OTHER(graph, e2, node);+            igraph_vector_int_t *edges2 = igraph_inclist_get(&incs, nei);+            int j, edgeslen2 = igraph_vector_int_size(edges2);+            for (j = 0; j < edgeslen2; j++) {+                int e2 = VECTOR(*edges2)[j];+                int nei2 = IGRAPH_OTHER(graph, e2, nei);+                igraph_real_t w2 = weights ? VECTOR(*weights)[e2] : 1;+                if (VECTOR(neis)[nei2] == node + 1) {+                    VECTOR(*res)[node] += w2;+                }+            }+        }++    } /* node < no_of_nodes */++    igraph_vector_int_destroy(&neis);+    igraph_inclist_destroy(&incs);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}++int igraph_i_local_scan_1_directed_all(const igraph_t *graph,+                                       igraph_vector_t *res,+                                       const igraph_vector_t *weights) {++    int no_of_nodes = igraph_vcount(graph);+    igraph_inclist_t incs;+    int i, node;++    igraph_vector_int_t neis;++    IGRAPH_CHECK(igraph_inclist_init(graph, &incs, IGRAPH_ALL));+    IGRAPH_FINALLY(igraph_inclist_destroy, &incs);++    igraph_vector_int_init(&neis, no_of_nodes);+    IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);++    igraph_vector_resize(res, no_of_nodes);+    igraph_vector_null(res);++    for (node = 0; node < no_of_nodes; node++) {+        igraph_vector_int_t *edges1 = igraph_inclist_get(&incs, node);+        int edgeslen1 = igraph_vector_int_size(edges1);++        IGRAPH_ALLOW_INTERRUPTION();++        /* Mark neighbors. We also count the edges that are incident to ego.+           Note that this time we do not mark ego, because we don't want to+           double count its incident edges later, when we are going over the+           incident edges of ego's neighbors. */+        for (i = 0; i < edgeslen1; i++) {+            int e = VECTOR(*edges1)[i];+            int nei = IGRAPH_OTHER(graph, e, node);+            igraph_real_t w = weights ? VECTOR(*weights)[e] : 1;+            VECTOR(neis)[nei] = node + 1;+            VECTOR(*res)[node] += w;+        }++        /* Crawl neighbors. We make sure that each neighbor of 'node' is+           only crawed once. We count all qualifying edges of ego, and+           then unmark ego to avoid double counting. */+        for (i = 0; i < edgeslen1; i++) {+            int e2 = VECTOR(*edges1)[i];+            int nei = IGRAPH_OTHER(graph, e2, node);+            igraph_vector_int_t *edges2;+            int j, edgeslen2;+            if (VECTOR(neis)[nei] != node + 1) {+                continue;+            }+            edges2 = igraph_inclist_get(&incs, nei);+            edgeslen2 = igraph_vector_int_size(edges2);+            for (j = 0; j < edgeslen2; j++) {+                int e2 = VECTOR(*edges2)[j];+                int nei2 = IGRAPH_OTHER(graph, e2, nei);+                igraph_real_t w2 = weights ? VECTOR(*weights)[e2] : 1;+                if (VECTOR(neis)[nei2] == node + 1) {+                    VECTOR(*res)[node] += w2;+                }+            }+            VECTOR(neis)[nei] = 0;+        }++    } /* node < no_of_nodes */++    igraph_vector_int_destroy(&neis);+    igraph_inclist_destroy(&incs);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}++int igraph_i_local_scan_1_sumweights(const igraph_t *graph,+                                     igraph_vector_t *res,+                                     const igraph_vector_t *weights) {++    long int no_of_nodes = igraph_vcount(graph);+    long int node, i, j, nn;+    igraph_inclist_t allinc;+    igraph_vector_int_t *neis1, *neis2;+    long int neilen1, neilen2;+    long int *neis;+    long int maxdegree;++    igraph_vector_int_t order;+    igraph_vector_int_t rank;+    igraph_vector_t degree, *edge1 = &degree; /* reuse degree as edge1 */++    if (igraph_vector_size(weights) != igraph_ecount(graph)) {+        IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+    }++    igraph_vector_int_init(&order, no_of_nodes);+    IGRAPH_FINALLY(igraph_vector_int_destroy, &order);+    IGRAPH_VECTOR_INIT_FINALLY(&degree, no_of_nodes);++    IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), IGRAPH_ALL,+                               IGRAPH_LOOPS));+    maxdegree = (long int) igraph_vector_max(&degree) + 1;+    igraph_vector_order1_int(&degree, &order, maxdegree);+    igraph_vector_int_init(&rank, no_of_nodes);+    IGRAPH_FINALLY(igraph_vector_int_destroy, &rank);+    for (i = 0; i < no_of_nodes; i++) {+        VECTOR(rank)[ VECTOR(order)[i] ] = no_of_nodes - i - 1;+    }++    IGRAPH_CHECK(igraph_inclist_init(graph, &allinc, IGRAPH_ALL));+    IGRAPH_FINALLY(igraph_inclist_destroy, &allinc);+    IGRAPH_CHECK(igraph_i_trans4_il_simplify(graph, &allinc, &rank));++    neis = igraph_Calloc(no_of_nodes, long int);+    if (neis == 0) {+        IGRAPH_ERROR("undirected local transitivity failed", IGRAPH_ENOMEM);+    }+    IGRAPH_FINALLY(igraph_free, neis);++    IGRAPH_CHECK(igraph_strength(graph, res, igraph_vss_all(), IGRAPH_ALL,+                                 IGRAPH_LOOPS, weights));++    for (nn = no_of_nodes - 1; nn >= 0; nn--) {+        node = VECTOR(order)[nn];++        IGRAPH_ALLOW_INTERRUPTION();++        neis1 = igraph_inclist_get(&allinc, node);+        neilen1 = igraph_vector_int_size(neis1);++        /* Mark the neighbors of the node */+        for (i = 0; i < neilen1; i++) {+            int edge = VECTOR(*neis1)[i];+            int nei = IGRAPH_OTHER(graph, edge, node);+            VECTOR(*edge1)[nei] = VECTOR(*weights)[edge];+            neis[nei] = node + 1;+        }++        for (i = 0; i < neilen1; i++) {+            long int edge = VECTOR(*neis1)[i];+            long int nei = IGRAPH_OTHER(graph, edge, node);+            igraph_real_t w = VECTOR(*weights)[edge];+            neis2 = igraph_inclist_get(&allinc, nei);+            neilen2 = igraph_vector_int_size(neis2);+            for (j = 0; j < neilen2; j++) {+                long int edge2 = VECTOR(*neis2)[j];+                long int nei2 = IGRAPH_OTHER(graph, edge2, nei);+                igraph_real_t w2 = VECTOR(*weights)[edge2];+                if (neis[nei2] == node + 1) {+                    VECTOR(*res)[node] += w2;+                    VECTOR(*res)[nei2] += w;+                    VECTOR(*res)[nei] += VECTOR(*edge1)[nei2];+                }+            }+        }+    }++    igraph_free(neis);+    igraph_inclist_destroy(&allinc);+    igraph_vector_int_destroy(&rank);+    igraph_vector_destroy(&degree);+    igraph_vector_int_destroy(&order);+    IGRAPH_FINALLY_CLEAN(5);++    return 0;+}++/**+ * \function igraph_local_scan_1_ecount+ * Local scan-statistics, k=1, edge count and sum of weights+ *+ * Count the number of edges or the sum the edge weights in the+ * 1-neighborhood of vertices.+ *+ * \param graph The input graph+ * \param res An initialized vector, the results are stored here.+ * \param weights Weight vector for weighted graphs, null pointer for+ *        unweighted graphs.+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.+ * \return Error code.+ *+ */++int igraph_local_scan_1_ecount(const igraph_t *graph, igraph_vector_t *res,+                               const igraph_vector_t *weights,+                               igraph_neimode_t mode) {++    if (igraph_is_directed(graph)) {+        if (mode != IGRAPH_ALL) {+            return igraph_i_local_scan_1_directed(graph, res, weights, mode);+        } else {+            return igraph_i_local_scan_1_directed_all(graph, res, weights);+        }+    } else {+        if (weights) {+            return igraph_i_local_scan_1_sumweights(graph, res, weights);+        } else {++#define TRIEDGES+#include "triangles_template.h"+#undef TRIEDGES++        }+    }++    return 0;+}++int igraph_i_local_scan_0_them_w(const igraph_t *us, const igraph_t *them,+                                 igraph_vector_t *res,+                                 const igraph_vector_t *weights_them,+                                 igraph_neimode_t mode) {++    igraph_t is;+    igraph_vector_t map2;+    int i, m;++    if (!weights_them) {+        IGRAPH_ERROR("Edge weights not given for weighted scan-0",+                     IGRAPH_EINVAL);+    }+    if (igraph_vector_size(weights_them) != igraph_ecount(them)) {+        IGRAPH_ERROR("Invalid weights length for scan-0", IGRAPH_EINVAL);+    }++    IGRAPH_VECTOR_INIT_FINALLY(&map2, 0);+    igraph_intersection(&is, us, them, /*map1=*/ 0, &map2);+    IGRAPH_FINALLY(igraph_destroy, &is);++    /* Rewrite the map as edge weights */+    m = igraph_vector_size(&map2);+    for (i = 0; i < m; i++) {+        VECTOR(map2)[i] = VECTOR(*weights_them)[ (int) VECTOR(map2)[i] ];+    }++    igraph_strength(&is, res, igraph_vss_all(), mode, IGRAPH_LOOPS,+                    /*weights=*/ &map2);++    igraph_destroy(&is);+    igraph_vector_destroy(&map2);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}++/**+ * \function igraph_local_scan_0_them+ * Local THEM scan-statistics, k=0+ *+ * K=0 scan-statistics is arbitrarily defined as the vertex degree for+ * unweighted, and the vertex strength for weighted graphs. See \ref+ * igraph_degree() and \ref igraph_strength().+ *+ * \param us The input graph, to use to extract the neighborhoods.+ * \param them The input graph to use for the actually counting.+ * \param res An initialized vector, the results are stored here.+ * \param weights_them Weight vector for weighted graphs, null pointer for+ *        unweighted graphs.+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.+ * \return Error code.+ *+ */++int igraph_local_scan_0_them(const igraph_t *us, const igraph_t *them,+                             igraph_vector_t *res,+                             const igraph_vector_t *weights_them,+                             igraph_neimode_t mode) {++    igraph_t is;++    if (igraph_vcount(us) != igraph_vcount(them)) {+        IGRAPH_ERROR("Number of vertices don't match in scan-0", IGRAPH_EINVAL);+    }+    if (igraph_is_directed(us) != igraph_is_directed(them)) {+        IGRAPH_ERROR("Directedness don't match in scan-0", IGRAPH_EINVAL);+    }++    if (weights_them) {+        return igraph_i_local_scan_0_them_w(us, them, res, weights_them, mode);+    }++    igraph_intersection(&is, us, them, /*edgemap1=*/ 0, /*edgemap2=*/ 0);+    IGRAPH_FINALLY(igraph_destroy, &is);++    igraph_degree(&is, res, igraph_vss_all(), mode, IGRAPH_LOOPS);++    igraph_destroy(&is);+    IGRAPH_FINALLY_CLEAN(1);++    return 0;+}++/**+ * \function igraph_local_scan_1_ecount_them+ * Local THEM scan-statistics, k=1, edge count and sum of weights+ *+ * Count the number of edges or the sum the edge weights in the+ * 1-neighborhood of vertices.+ *+ * \param us The input graph to extract the neighborhoods.+ * \param them The input graph to perform the counting.+ * \param weights_them Weight vector for weighted graphs, null pointer for+ *        unweighted graphs.+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.+ * \return Error code.+ *+ * \sa \ref igraph_local_scan_1_ecount() for the US statistics.+ */++int igraph_local_scan_1_ecount_them(const igraph_t *us, const igraph_t *them,+                                    igraph_vector_t *res,+                                    const igraph_vector_t *weights_them,+                                    igraph_neimode_t mode) {++    int no_of_nodes = igraph_vcount(us);+    igraph_adjlist_t adj_us;+    igraph_inclist_t incs_them;+    igraph_vector_int_t neis;+    int node;++    if (igraph_vcount(them) != no_of_nodes) {+        IGRAPH_ERROR("Number of vertices must match in scan-1", IGRAPH_EINVAL);+    }+    if (igraph_is_directed(us) != igraph_is_directed(them)) {+        IGRAPH_ERROR("Directedness must match in scan-1", IGRAPH_EINVAL);+    }+    if (weights_them &&+        igraph_vector_size(weights_them) != igraph_ecount(them)) {+        IGRAPH_ERROR("Invalid weight vector length in scan-1 (them)",+                     IGRAPH_EINVAL);+    }++    igraph_adjlist_init(us, &adj_us, mode);+    IGRAPH_FINALLY(igraph_adjlist_destroy, &adj_us);+    igraph_adjlist_simplify(&adj_us);+    igraph_inclist_init(them, &incs_them, mode);+    IGRAPH_FINALLY(igraph_inclist_destroy, &incs_them);++    igraph_vector_int_init(&neis, no_of_nodes);+    IGRAPH_FINALLY(igraph_vector_int_destroy, &neis);++    igraph_vector_resize(res, no_of_nodes);+    igraph_vector_null(res);++    for (node = 0; node < no_of_nodes; node++) {+        igraph_vector_int_t *neis_us = igraph_adjlist_get(&adj_us, node);+        igraph_vector_int_t *edges1_them = igraph_inclist_get(&incs_them, node);+        int len1_us = igraph_vector_int_size(neis_us);+        int len1_them = igraph_vector_int_size(edges1_them);+        int i;++        IGRAPH_ALLOW_INTERRUPTION();++        /* Mark neighbors and self in us */+        VECTOR(neis)[node] = node + 1;+        for (i = 0; i < len1_us; i++) {+            int nei = VECTOR(*neis_us)[i];+            VECTOR(neis)[nei] = node + 1;+        }++        /* Crawl neighbors in them, first ego */+        for (i = 0; i < len1_them; i++) {+            int e = VECTOR(*edges1_them)[i];+            int nei = IGRAPH_OTHER(them, e, node);+            if (VECTOR(neis)[nei] == node + 1) {+                igraph_real_t w = weights_them ? VECTOR(*weights_them)[e] : 1;+                VECTOR(*res)[node] += w;+            }+        }+        /* Then the rest */+        for (i = 0; i < len1_us; i++) {+            int nei = VECTOR(*neis_us)[i];+            igraph_vector_int_t *edges2_them = igraph_inclist_get(&incs_them, nei);+            int j, len2_them = igraph_vector_int_size(edges2_them);+            for (j = 0; j < len2_them; j++) {+                int e2 = VECTOR(*edges2_them)[j];+                int nei2 = IGRAPH_OTHER(them, e2, nei);+                if (VECTOR(neis)[nei2] == node + 1) {+                    igraph_real_t w = weights_them ? VECTOR(*weights_them)[e2] : 1;+                    VECTOR(*res)[node] += w;+                }+            }+        }++        /* For undirected, it was double counted */+        if (mode == IGRAPH_ALL || ! igraph_is_directed(us)) {+            VECTOR(*res)[node] /= 2.0;+        }++    } /* node < no_of_nodes */++    igraph_vector_int_destroy(&neis);+    igraph_inclist_destroy(&incs_them);+    igraph_adjlist_destroy(&adj_us);+    IGRAPH_FINALLY_CLEAN(3);++    return 0;+}++/**+ * \function igraph_local_scan_k_ecount+ * Local scan-statistics, general function, edge count and sum of weights+ *+ * Count the number of edges or the sum the edge weights in the+ * k-neighborhood of vertices.+ *+ * \param graph The input graph+ * \param k The size of the neighborhood, non-negative integer.+ *        The k=0 case is special, see \ref igraph_local_scan_0().+ * \param res An initialized vector, the results are stored here.+ * \param weights Weight vector for weighted graphs, null pointer for+ *        unweighted graphs.+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.+ * \return Error code.+ *+ */++int igraph_local_scan_k_ecount(const igraph_t *graph, int k,+                               igraph_vector_t *res,+                               const igraph_vector_t *weights,+                               igraph_neimode_t mode) {++    int no_of_nodes = igraph_vcount(graph);+    int node;+    igraph_dqueue_int_t Q;+    igraph_vector_int_t marked;+    igraph_inclist_t incs;++    if (k < 0) {+        IGRAPH_ERROR("k must be non-negative in k-scan", IGRAPH_EINVAL);+    }+    if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {+        IGRAPH_ERROR("Invalid weight vector length in k-scan", IGRAPH_EINVAL);+    }++    if (k == 0) {+        return igraph_local_scan_0(graph, res, weights, mode);+    }+    if (k == 1) {+        return igraph_local_scan_1_ecount(graph, res, weights, mode);+    }++    /* We do a BFS form each node, and simply count the number+       of edges on the way */++    IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100));+    IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q);+    IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);+    IGRAPH_CHECK(igraph_inclist_init(graph, &incs, mode));+    IGRAPH_FINALLY(igraph_inclist_destroy, &incs);++    IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));+    igraph_vector_null(res);++    for (node = 0 ; node < no_of_nodes ; node++) {+        igraph_dqueue_int_push(&Q, node);+        igraph_dqueue_int_push(&Q, 0);+        VECTOR(marked)[node] = node + 1;+        while (!igraph_dqueue_int_empty(&Q)) {+            int act = igraph_dqueue_int_pop(&Q);+            int dist = igraph_dqueue_int_pop(&Q) + 1;+            igraph_vector_int_t *edges = igraph_inclist_get(&incs, act);+            int i, edgeslen = igraph_vector_int_size(edges);+            for (i = 0; i < edgeslen; i++) {+                int edge = VECTOR(*edges)[i];+                int nei = IGRAPH_OTHER(graph, edge, act);+                if (dist <= k || VECTOR(marked)[nei] == node + 1) {+                    igraph_real_t w = weights ? VECTOR(*weights)[edge] : 1;+                    VECTOR(*res)[node] += w;+                }+                if (dist <= k && VECTOR(marked)[nei] != node + 1) {+                    igraph_dqueue_int_push(&Q, nei);+                    igraph_dqueue_int_push(&Q, dist);+                    VECTOR(marked)[nei] = node + 1;+                }+            }+        }++        if (mode == IGRAPH_ALL || ! igraph_is_directed(graph)) {+            VECTOR(*res)[node] /= 2.0;+        }++    } /* node < no_of_nodes */++    igraph_inclist_destroy(&incs);+    igraph_vector_int_destroy(&marked);+    igraph_dqueue_int_destroy(&Q);+    IGRAPH_FINALLY_CLEAN(3);++    return 0;+}++/**+ * \function igraph_local_scan_k_ecount_them+ * Local THEM scan-statistics, general function, edge count and sum of weights+ *+ * Count the number of edges or the sum the edge weights in the+ * k-neighborhood of vertices.+ *+ * \param us The input graph to extract the neighborhoods.+ * \param them The input graph to perform the counting.+ * \param k The size of the neighborhood, non-negative integer.+ *        The k=0 case is special, see \ref igraph_local_scan_0_them().+ * \param weights_them Weight vector for weighted graphs, null pointer for+ *        unweighted graphs.+ * \param mode Type of the neighborhood, \c IGRAPH_OUT means outgoing,+ *        \c IGRAPH_IN means incoming and \c IGRAPH_ALL means all edges.+ * \return Error code.+ *+ * \sa \ref igraph_local_scan_1_ecount() for the US statistics.+ */++int igraph_local_scan_k_ecount_them(const igraph_t *us, const igraph_t *them,+                                    int k, igraph_vector_t *res,+                                    const igraph_vector_t *weights_them,+                                    igraph_neimode_t mode) {++    int no_of_nodes = igraph_vcount(us);+    int node;+    igraph_dqueue_int_t Q;+    igraph_vector_int_t marked;+    igraph_stack_int_t ST;+    igraph_inclist_t incs_us, incs_them;++    if (igraph_vcount(them) != no_of_nodes) {+        IGRAPH_ERROR("Number of vertices must match in scan-k", IGRAPH_EINVAL);+    }+    if (igraph_is_directed(us) != igraph_is_directed(them)) {+        IGRAPH_ERROR("Directedness must match in scan-k", IGRAPH_EINVAL);+    }+    if (k < 0) {+        IGRAPH_ERROR("k must be non-negative in k-scan", IGRAPH_EINVAL);+    }+    if (weights_them &&+        igraph_vector_size(weights_them) != igraph_ecount(them)) {+        IGRAPH_ERROR("Invalid weight vector length in k-scan (them)",+                     IGRAPH_EINVAL);+    }++    if (k == 0) {+        return igraph_local_scan_0_them(us, them, res, weights_them, mode);+    }+    if (k == 1) {+        return igraph_local_scan_1_ecount_them(us, them, res, weights_them, mode);+    }++    /* We mark the nodes in US in a BFS. Then we check the outgoing edges+       of all marked nodes in THEM. */++    IGRAPH_CHECK(igraph_dqueue_int_init(&Q, 100));+    IGRAPH_FINALLY(igraph_dqueue_int_destroy, &Q);+    IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);+    IGRAPH_CHECK(igraph_inclist_init(us, &incs_us, mode));+    IGRAPH_FINALLY(igraph_inclist_destroy, &incs_us);+    IGRAPH_CHECK(igraph_inclist_init(them, &incs_them, mode));+    IGRAPH_FINALLY(igraph_inclist_destroy, &incs_them);+    IGRAPH_CHECK(igraph_stack_int_init(&ST, 100));+    IGRAPH_FINALLY(igraph_stack_int_destroy, &ST);++    IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));+    igraph_vector_null(res);++    for (node = 0; node < no_of_nodes; node++) {++        /* BFS to mark the nodes in US */+        IGRAPH_CHECK(igraph_dqueue_int_push(&Q, node));+        IGRAPH_CHECK(igraph_dqueue_int_push(&Q, 0));+        IGRAPH_CHECK(igraph_stack_int_push(&ST, node));+        VECTOR(marked)[node] = node + 1;+        while (!igraph_dqueue_int_empty(&Q)) {+            int act = igraph_dqueue_int_pop(&Q);+            int dist = igraph_dqueue_int_pop(&Q) + 1;+            igraph_vector_int_t *edges = igraph_inclist_get(&incs_us, act);+            int i, edgeslen = igraph_vector_int_size(edges);+            for (i = 0; i < edgeslen; i++) {+                int edge = VECTOR(*edges)[i];+                int nei = IGRAPH_OTHER(us, edge, act);+                if (dist <= k && VECTOR(marked)[nei] != node + 1) {+                    igraph_dqueue_int_push(&Q, nei);+                    igraph_dqueue_int_push(&Q, dist);+                    VECTOR(marked)[nei] = node + 1;+                    igraph_stack_int_push(&ST, nei);+                }+            }+        }++        /* Now check the edges of all nodes in THEM */+        while (!igraph_stack_int_empty(&ST)) {+            int act = igraph_stack_int_pop(&ST);+            igraph_vector_int_t *edges = igraph_inclist_get(&incs_them, act);+            int i, edgeslen = igraph_vector_int_size(edges);+            for (i = 0; i < edgeslen; i++) {+                int edge = VECTOR(*edges)[i];+                int nei = IGRAPH_OTHER(them, edge, act);+                if (VECTOR(marked)[nei] == node + 1) {+                    igraph_real_t w = weights_them ? VECTOR(*weights_them)[edge] : 1;+                    VECTOR(*res)[node] += w;+                }+            }+        }++        if (mode == IGRAPH_ALL || ! igraph_is_directed(us)) {+            VECTOR(*res)[node] /= 2;+        }++    } /* node < no_of_nodes */++    igraph_stack_int_destroy(&ST);+    igraph_inclist_destroy(&incs_them);+    igraph_inclist_destroy(&incs_us);+    igraph_vector_int_destroy(&marked);+    igraph_dqueue_int_destroy(&Q);+    IGRAPH_FINALLY_CLEAN(5);++    return 0;+}++/**+ * \function igraph_local_scan_neighborhood_ecount+ * Local scan-statistics with pre-calculated neighborhoods+ *+ * Count the number of edges, or sum the edge weigths in+ * neighborhoods given as a parameter.+ *+ * \param graph The graph to perform the counting/summing in.+ * \param res Initialized vector, the result is stored here.+ * \param weights Weight vector for weighted graphs, null pointer for+ *        unweighted graphs.+ * \param neighborhoods List of <code>igraph_vector_int_t</code>+ *        objects, the neighborhoods, one for each vertex in the+ *        graph.+ * \return Error code.+ */++int igraph_local_scan_neighborhood_ecount(const igraph_t *graph,+        igraph_vector_t *res,+        const igraph_vector_t *weights,+        const igraph_vector_ptr_t *neighborhoods) {++    int node, no_of_nodes = igraph_vcount(graph);+    igraph_inclist_t incs;+    igraph_vector_int_t marked;+    igraph_bool_t directed = igraph_is_directed(graph);++    if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) {+        IGRAPH_ERROR("Invalid weight vector length in local scan", IGRAPH_EINVAL);+    }+    if (igraph_vector_ptr_size(neighborhoods) != no_of_nodes) {+        IGRAPH_ERROR("Invalid neighborhood list length in local scan",+                     IGRAPH_EINVAL);+    }++    IGRAPH_CHECK(igraph_vector_int_init(&marked, no_of_nodes));+    IGRAPH_FINALLY(igraph_vector_int_destroy, &marked);+    IGRAPH_CHECK(igraph_inclist_init(graph, &incs, IGRAPH_OUT));+    IGRAPH_FINALLY(igraph_inclist_destroy, &incs);++    IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));+    igraph_vector_null(res);++    for (node = 0; node < no_of_nodes; node++) {+        igraph_vector_int_t *nei = VECTOR(*neighborhoods)[node];+        int i, neilen = igraph_vector_int_size(nei);+        VECTOR(marked)[node] = node + 1;+        for (i = 0; i < neilen; i++) {+            int vertex = VECTOR(*nei)[i];+            if (vertex < 0 || vertex >= no_of_nodes) {+                IGRAPH_ERROR("Invalid vertex id in neighborhood list in local scan",+                             IGRAPH_EINVAL);+            }+            VECTOR(marked)[vertex] = node + 1;+        }++        for (i = 0; i < neilen; i++) {+            int vertex = VECTOR(*nei)[i];+            igraph_vector_int_t *edges = igraph_inclist_get(&incs, vertex);+            int j, edgeslen = igraph_vector_int_size(edges);+            for (j = 0; j < edgeslen; j++) {+                int edge = VECTOR(*edges)[j];+                int nei2 = IGRAPH_OTHER(graph, edge, vertex);+                if (VECTOR(marked)[nei2] == node + 1) {+                    igraph_real_t w = weights ? VECTOR(*weights)[edge] : 1;+                    VECTOR(*res)[node] += w;+                }+            }+        }+        if (!directed) {+            VECTOR(*res)[node] /= 2.0;+        }+    }++    igraph_inclist_destroy(&incs);+    igraph_vector_int_destroy(&marked);+    IGRAPH_FINALLY_CLEAN(2);++    return 0;+}
+ igraph/src/scg.c view
@@ -0,0 +1,2292 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-12  Gabor Csardi <csardi.gabor@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@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' &lt; 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'| &lt;= 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;+}
+ igraph/src/scg_approximate_methods.c view
@@ -0,0 +1,173 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2011-12  Gabor Csardi <csardi.gabor@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@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;+}
+ igraph/src/scg_exact_scg.c view
@@ -0,0 +1,68 @@+/*+ *  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@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;+}++
+ igraph/src/scg_kmeans.c view
@@ -0,0 +1,105 @@+/*+ *  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@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;+}+
+ igraph/src/scg_optimal_method.c view
@@ -0,0 +1,241 @@+/*+ *  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@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;+}+
+ igraph/src/scg_utils.c view
@@ -0,0 +1,94 @@+/*+ *  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@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;+}
+ igraph/src/second.c view
@@ -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_ */+
+ igraph/src/separators.c view
@@ -0,0 +1,836 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 at least 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 = 0;+            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_CHECK(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_CHECK(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, which must be undirected.+ * \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;++    if (igraph_is_directed(graph)) {+        IGRAPH_ERROR("Minimum size separators currently only works on undirected graphs",+                     IGRAPH_EINVAL);+    }++    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;+}
+ igraph/src/sfe.c view
@@ -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
+ igraph/src/sig_die.c view
@@ -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
+ igraph/src/signal_.c view
@@ -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
+ igraph/src/signbit.c view
@@ -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;+	}
+ igraph/src/sir.c view
@@ -0,0 +1,263 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2014  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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. A simulation+ * is stopped when no infected individuals are left.+ *+ * \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_psumtree_reset(&tree);+        }++        /* 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);+        }++        while (ni > 0) {+            igraph_real_t tt;+            igraph_real_t r;+            long int vchange;++            psum = igraph_psumtree_sum(&tree);+            tt = igraph_rng_get_exp(igraph_rng_default(), psum);+            r = RNG_UNIF(0, psum);++            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++;+                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);+                        igraph_psumtree_update(&tree, nei, rate - beta);+                    }+                }++            } else { /* S_S */+                VECTOR(status)[vchange] = S_I;+                ns--; ni++;+                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);+                        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;+}
+ igraph/src/spanning_trees.c view
@@ -0,0 +1,521 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2011  Gabor Csardi <csardi.gabor@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_adjlist.h"+#include "igraph_random.h"+#include "igraph_components.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;+}+++/* igraph_random_spanning_tree */++/* Loop-erased random walk (LERW) implementation.+ * res must be an initialized vector. The edge IDs of the spanning tree+ * will be added to the end of it. res will not be cleared before doing this.+ *+ * The walk is started from vertex start. comp_size must be the size of the connected+ * component containing start.+ */+static int igraph_i_lerw(const igraph_t *graph, igraph_vector_t *res, igraph_integer_t start,+                         igraph_integer_t comp_size, igraph_vector_bool_t *visited, const igraph_inclist_t *il) {+    igraph_integer_t visited_count;++    IGRAPH_CHECK(igraph_vector_reserve(res, igraph_vector_size(res) + comp_size - 1));++    RNG_BEGIN();++    VECTOR(*visited)[start] = 1;+    visited_count = 1;++    while (visited_count < comp_size) {+        long degree, edge;+        igraph_vector_int_t *edges;++        edges = igraph_inclist_get(il, start);++        /* choose a random edge */+        degree = igraph_vector_int_size(edges);+        edge = VECTOR(*edges)[ RNG_INTEGER(0, degree - 1) ];++        /* set 'start' to the next vertex */+        start = IGRAPH_OTHER(graph, edge, start);++        /* if the next vertex hasn't been visited yet, register the edge we just traversed */+        if (! VECTOR(*visited)[start]) {+            IGRAPH_CHECK(igraph_vector_push_back(res, edge));+            VECTOR(*visited)[start] = 1;+            visited_count++;+        }++        IGRAPH_ALLOW_INTERRUPTION();+    }++    RNG_END();++    return IGRAPH_SUCCESS;+}++/**+ * \function igraph_random_spanning_tree+ * \brief Uniformly sample the spanning trees of a graph+ *+ * Performs a loop-erased random walk on the graph to uniformly sample+ * its spanning trees. Edge directions are ignored.+ * </para><para>+ *+ * Multi-graphs are supported, and edge multiplicities will affect the sampling+ * frequency. For example, consider the 3-cycle graph <code>1=2-3-1</code>, with two edges+ * between vertices 1 and 2. Due to these parallel edges, the trees <code>1-2-3</code>+ * and <code>3-1-2</code> will be sampled with multiplicity 2, while the tree+ * <code>2-3-1</code> will be sampled with multiplicity 1.+ *+ * \param graph The input graph. Edge directions are ignored.+ * \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 vid This parameter is relevant if the graph is not connected.+ *        If negative, a random spanning forest of all components will be+ *        generated. Otherwise, it should be the ID of a vertex. A random+ *        spanning tree of the component containing the vertex will be+ *        generated.+ *+ * \return Error code.+ *+ * \sa \ref igraph_minimum_spanning_tree(), \ref igraph_random_walk()+ *+ */+int igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_t *res, igraph_integer_t vid) {+    igraph_inclist_t il;+    igraph_vector_bool_t visited;+    igraph_integer_t vcount = igraph_vcount(graph);++    if (vid >= vcount) {+        IGRAPH_ERROR("Invalid vertex id given for random spanning tree", IGRAPH_EINVVID);+    }++    IGRAPH_CHECK(igraph_inclist_init(graph, &il, IGRAPH_ALL));+    IGRAPH_FINALLY(igraph_inclist_destroy, &il);++    IGRAPH_CHECK(igraph_vector_bool_init(&visited, vcount));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &visited);++    igraph_vector_clear(res);++    if (vid < 0) { /* generate random spanning forest: consider each component separately */+        igraph_vector_t membership, csize;+        igraph_integer_t comp_count;+        igraph_integer_t i;++        IGRAPH_VECTOR_INIT_FINALLY(&membership, 0);+        IGRAPH_VECTOR_INIT_FINALLY(&csize, 0);++        IGRAPH_CHECK(igraph_clusters(graph, &membership, &csize, &comp_count, IGRAPH_WEAK));++        /* for each component ... */+        for (i = 0; i < comp_count; ++i) {+            /* ... find a vertex to start the LERW from */+            igraph_integer_t j = 0;+            while (VECTOR(membership)[j] != i) {+                ++j;+            }++            IGRAPH_CHECK(igraph_i_lerw(graph, res, j, (igraph_integer_t) VECTOR(csize)[i], &visited, &il));+        }++        igraph_vector_destroy(&membership);+        igraph_vector_destroy(&csize);+        IGRAPH_FINALLY_CLEAN(2);+    } else { /* consider the component containing vid */+        igraph_vector_t comp_vertices;+        igraph_integer_t comp_size;++        /* we measure the size of the component */+        IGRAPH_VECTOR_INIT_FINALLY(&comp_vertices, 0);+        IGRAPH_CHECK(igraph_subcomponent(graph, &comp_vertices, vid, IGRAPH_ALL));+        comp_size = (igraph_integer_t) igraph_vector_size(&comp_vertices);+        igraph_vector_destroy(&comp_vertices);+        IGRAPH_FINALLY_CLEAN(1);++        IGRAPH_CHECK(igraph_i_lerw(graph, res, vid, comp_size, &visited, &il));+    }++    igraph_vector_bool_destroy(&visited);+    igraph_inclist_destroy(&il);+    IGRAPH_FINALLY_CLEAN(2);++    return IGRAPH_SUCCESS;+}+
+ igraph/src/sparsemat.c view
@@ -0,0 +1,3055 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2009-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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://faculty.cse.tamu.edu/davis/suitesparse.html+ * </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 = &num;+        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_rowmins_triplet(const igraph_sparsemat_t *A,+                                       igraph_vector_t *res) {+    int i;+    int *pi = A->cs->i;+    double *px = A->cs->x;+    double inf = IGRAPH_INFINITY;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));+    igraph_vector_fill(res, inf);++    for (i = 0; i < A->cs->nz; i++, pi++, px++) {+        if (*px < VECTOR(*res)[ *pi ]) {+            VECTOR(*res)[ *pi ] = *px;+        }+    }++    return 0;+}++int igraph_i_sparsemat_rowmins_cc(igraph_sparsemat_t *A,+                                  igraph_vector_t *res) {+    int ne;+    double *px;+    int *pi;+    double inf = IGRAPH_INFINITY;++    IGRAPH_CHECK(igraph_sparsemat_dupl(A));++    ne = A->cs->p[A->cs->n];+    px = A->cs->x;+    pi = A->cs->i;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));+    igraph_vector_fill(res, inf);++    for (; pi < A->cs->i + ne; pi++, px++) {+        if (*px < VECTOR(*res)[ *pi ]) {+            VECTOR(*res)[ *pi ] = *px;+        }+    }++    return 0;+}++int igraph_sparsemat_rowmins(igraph_sparsemat_t *A,+                             igraph_vector_t *res) {+    if (igraph_sparsemat_is_triplet(A)) {+        return igraph_i_sparsemat_rowmins_triplet(A, res);+    } else {+        return igraph_i_sparsemat_rowmins_cc(A, res);+    }+}+++int igraph_i_sparsemat_rowmaxs_triplet(const igraph_sparsemat_t *A,+                                       igraph_vector_t *res) {+    int i;+    int *pi = A->cs->i;+    double *px = A->cs->x;+    double inf = IGRAPH_NEGINFINITY;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));+    igraph_vector_fill(res, inf);++    for (i = 0; i < A->cs->nz; i++, pi++, px++) {+        if (*px > VECTOR(*res)[ *pi ]) {+            VECTOR(*res)[ *pi ] = *px;+        }+    }++    return 0;+}++int igraph_i_sparsemat_rowmaxs_cc(igraph_sparsemat_t *A,+                                  igraph_vector_t *res) {+    int ne;+    double *px;+    int *pi;+    double inf = IGRAPH_NEGINFINITY;++    IGRAPH_CHECK(igraph_sparsemat_dupl(A));++    ne = A->cs->p[A->cs->n];+    px = A->cs->x;+    pi = A->cs->i;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));+    igraph_vector_fill(res, inf);++    for (; pi < A->cs->i + ne; pi++, px++) {+        if (*px > VECTOR(*res)[ *pi ]) {+            VECTOR(*res)[ *pi ] = *px;+        }+    }++    return 0;+}++int igraph_sparsemat_rowmaxs(igraph_sparsemat_t *A,+                             igraph_vector_t *res) {+    if (igraph_sparsemat_is_triplet(A)) {+        return igraph_i_sparsemat_rowmaxs_triplet(A, res);+    } else {+        return igraph_i_sparsemat_rowmaxs_cc(A, res);+    }+}++int igraph_i_sparsemat_colmins_triplet(const igraph_sparsemat_t *A,+                                       igraph_vector_t *res) {+    int i;+    int *pp = A->cs->p;+    double *px = A->cs->x;+    double inf = IGRAPH_INFINITY;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->n));+    igraph_vector_fill(res, inf);++    for (i = 0; i < A->cs->nz; i++, pp++, px++) {+        if (*px < VECTOR(*res)[ *pp ]) {+            VECTOR(*res)[ *pp ] = *px;+        }+    }++    return 0;+}++int igraph_i_sparsemat_colmins_cc(igraph_sparsemat_t *A,+                                  igraph_vector_t *res) {+    int n;+    double *px;+    int *pp;+    int *pi;+    double *pr;+    double inf = IGRAPH_INFINITY;++    IGRAPH_CHECK(igraph_sparsemat_dupl(A));++    n = A->cs->n;+    px = A->cs->x;+    pp = A->cs->p;+    pi = A->cs->i;++    IGRAPH_CHECK(igraph_vector_resize(res, n));+    igraph_vector_fill(res, inf);+    pr = VECTOR(*res);++    for (; pp < A->cs->p + n; pp++, pr++) {+        for (; pi < A->cs->i + * (pp + 1); pi++, px++) {+            if (*px < *pr) {+                *pr = *px;+            }+        }+    }+    return 0;+}++int igraph_sparsemat_colmins(igraph_sparsemat_t *A,+                             igraph_vector_t *res) {+    if (igraph_sparsemat_is_triplet(A)) {+        return igraph_i_sparsemat_colmins_triplet(A, res);+    } else {+        return igraph_i_sparsemat_colmins_cc(A, res);+    }+}++int igraph_i_sparsemat_colmaxs_triplet(const igraph_sparsemat_t *A,+                                       igraph_vector_t *res) {+    int i;+    int *pp = A->cs->p;+    double *px = A->cs->x;+    double inf = IGRAPH_NEGINFINITY;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->n));+    igraph_vector_fill(res, inf);++    for (i = 0; i < A->cs->nz; i++, pp++, px++) {+        if (*px > VECTOR(*res)[ *pp ]) {+            VECTOR(*res)[ *pp ] = *px;+        }+    }++    return 0;+}++int igraph_i_sparsemat_colmaxs_cc(igraph_sparsemat_t *A,+                                  igraph_vector_t *res) {+    int n;+    double *px;+    int *pp;+    int *pi;+    double *pr;+    double inf = IGRAPH_NEGINFINITY;++    IGRAPH_CHECK(igraph_sparsemat_dupl(A));++    n = A->cs->n;+    px = A->cs->x;+    pp = A->cs->p;+    pi = A->cs->i;++    IGRAPH_CHECK(igraph_vector_resize(res, n));+    igraph_vector_fill(res, inf);+    pr = VECTOR(*res);++    for (; pp < A->cs->p + n; pp++, pr++) {+        for (; pi < A->cs->i + * (pp + 1); pi++, px++) {+            if (*px > *pr) {+                *pr = *px;+            }+        }+    }+    return 0;+}++int igraph_sparsemat_colmaxs(igraph_sparsemat_t *A,+                             igraph_vector_t *res) {+    if (igraph_sparsemat_is_triplet(A)) {+        return igraph_i_sparsemat_colmaxs_triplet(A, res);+    } else {+        return igraph_i_sparsemat_colmaxs_cc(A, res);+    }+}++int igraph_i_sparsemat_which_min_rows_triplet(igraph_sparsemat_t *A,+        igraph_vector_t *res,+        igraph_vector_int_t *pos) {+    int i;+    int *pi = A->cs->i;+    int *pp = A->cs->p;+    double *px = A->cs->x;+    double inf = IGRAPH_INFINITY;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));+    IGRAPH_CHECK(igraph_vector_int_resize(pos, A->cs->m));+    igraph_vector_fill(res, inf);+    igraph_vector_int_null(pos);++    for (i = 0; i < A->cs->nz; i++, pi++, px++, pp++) {+        if (*px < VECTOR(*res)[ *pi ]) {+            VECTOR(*res)[ *pi ] = *px;+            VECTOR(*pos)[ *pi ] = *pp;+        }+    }++    return 0;+}++int igraph_i_sparsemat_which_min_rows_cc(igraph_sparsemat_t *A,+        igraph_vector_t *res,+        igraph_vector_int_t *pos) {+    int n;+    double *px;+    int *pp;+    int *pi;+    double inf = IGRAPH_INFINITY;+    int j;++    IGRAPH_CHECK(igraph_sparsemat_dupl(A));++    n = A->cs->n;+    px = A->cs->x;+    pp = A->cs->p;+    pi = A->cs->i;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->m));+    IGRAPH_CHECK(igraph_vector_int_resize(pos, A->cs->m));+    igraph_vector_fill(res, inf);+    igraph_vector_int_null(pos);++    for (j = 0; pp < A->cs->p + n; pp++, j++) {+        for (; pi < A->cs->i + * (pp + 1); pi++, px++) {+            if (*px < VECTOR(*res)[ *pi ]) {+                VECTOR(*res)[ *pi ] = *px;+                VECTOR(*pos)[ *pi ] = j;+            }+        }+    }++    return 0;+}++int igraph_sparsemat_which_min_rows(igraph_sparsemat_t *A,+                                    igraph_vector_t *res,+                                    igraph_vector_int_t *pos) {+    if (igraph_sparsemat_is_triplet(A)) {+        return igraph_i_sparsemat_which_min_rows_triplet(A, res, pos);+    } else {+        return igraph_i_sparsemat_which_min_rows_cc(A, res, pos);+    }+}++int igraph_i_sparsemat_which_min_cols_triplet(igraph_sparsemat_t *A,+        igraph_vector_t *res,+        igraph_vector_int_t *pos) {++    int i;+    int *pi = A->cs->i;+    int *pp = A->cs->p;+    double *px = A->cs->x;+    double inf = IGRAPH_INFINITY;++    IGRAPH_CHECK(igraph_vector_resize(res, A->cs->n));+    IGRAPH_CHECK(igraph_vector_int_resize(pos, A->cs->n));+    igraph_vector_fill(res, inf);+    igraph_vector_int_null(pos);++    for (i = 0; i < A->cs->nz; i++, pi++, pp++, px++) {+        if (*px < VECTOR(*res)[ *pp ]) {+            VECTOR(*res)[ *pp ] = *px;+            VECTOR(*pos)[ *pp ] = *pi;+        }+    }++    return 0;+}++int igraph_i_sparsemat_which_min_cols_cc(igraph_sparsemat_t *A,+        igraph_vector_t *res,+        igraph_vector_int_t *pos) {+    int n, j, p;+    double *px;+    double *pr;+    int *ppos;+    double inf = IGRAPH_INFINITY;++    IGRAPH_CHECK(igraph_sparsemat_dupl(A));++    n = A->cs->n;+    px = A->cs->x;++    IGRAPH_CHECK(igraph_vector_resize(res, n));+    igraph_vector_fill(res, inf);+    pr = VECTOR(*res);+    IGRAPH_CHECK(igraph_vector_int_resize(pos, n));+    igraph_vector_int_null(pos);+    ppos = VECTOR(*pos);++    for (j = 0; j < A->cs->n; j++, pr++, ppos++) {+        for (p = A->cs->p[j]; p < A->cs->p[j + 1]; p++, px++) {+            if (*px < *pr) {+                *pr = *px;+                *ppos = A->cs->i[p];+            }+        }+    }+    return 0;+}++int igraph_sparsemat_which_min_cols(igraph_sparsemat_t *A,+                                    igraph_vector_t *res,+                                    igraph_vector_int_t *pos) {+    if (igraph_sparsemat_is_triplet(A)) {+        return igraph_i_sparsemat_which_min_cols_triplet(A, res, pos);+    } else {+        return igraph_i_sparsemat_which_min_cols_cc(A, res, pos);+    }+}++int igraph_i_sparsemat_colsums_triplet(const igraph_sparsemat_t *A,+                                       igraph_vector_t *res) {+    int i;+    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;+}
+ igraph/src/spectral_properties.c view
@@ -0,0 +1,436 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_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);++    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;+}
+ igraph/src/spmatrix.c view
@@ -0,0 +1,1053 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}++
+ igraph/src/st-cuts.c view
@@ -0,0 +1,1549 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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, n;+    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;+                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);+            }+        }+    }++    /* Relabel left out vertices (set K in Provan & Shier) to+       correspond to node labelling of graph instead of SBar.+       At the same time ensure that GammaS is a proper subset of+       L, where L are the nodes in the dominator tree. */+    n = igraph_vector_size(&leftout);+    for (i = 0; i < n; i++) {+        VECTOR(leftout)[i] = VECTOR(Sbar_invmap)[(long int)VECTOR(leftout)[i]];+        VECTOR(GammaS)[(long int)VECTOR(leftout)[i]] = 0;+    }++    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;+    igraph_vector_ptr_t *mypartition1s = partition1s, vpartition1s;+    long int i, nocuts;++    if (!igraph_is_directed(graph)) {+        IGRAPH_ERROR("Listing all s-t cuts only implemented for "+                     "directed graphs", IGRAPH_UNIMPLEMENTED);+    }++    if (!partition1s) {+        mypartition1s = &vpartition1s;+        IGRAPH_CHECK(igraph_vector_ptr_init(mypartition1s, 0));+        IGRAPH_FINALLY(igraph_vector_ptr_destroy, mypartition1s);+    } else {+        igraph_vector_ptr_clear(mypartition1s);+    }++    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);+    }++    /* We call it with S={}, T={} */+    IGRAPH_CHECK(igraph_provan_shier_list(graph, &S, &T,+                                          source, target, mypartition1s,+                                          igraph_i_all_st_cuts_pivot,+                                          /*pivot_arg=*/ 0));++    nocuts = igraph_vector_ptr_size(mypartition1s);++    if (cuts) {+        igraph_vector_long_t inS;+        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(*mypartition1s)[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);++    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;+}++/* 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_VECTOR_INIT_FINALLY(&neis, 0);+    IGRAPH_VECTOR_INIT_FINALLY(&indeg, no_of_nodes);++    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)) {+            long int j, n;+            IGRAPH_CHECK(igraph_neighbors(Sbar, &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];+                VECTOR(indeg)[nei] -= 1;+            }+        }+    }++    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_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, j;+    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 (min != target)+            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;+        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 (j = 0; j < no_of_nodes; j++) {+            igraph_real_t u = VECTOR(Isv_min)[j];+            if (!IGRAPH_FINITE(u)) {+                break;+            }+            if (!igraph_estack_iselement(T, u)) {+                IGRAPH_CHECK(igraph_vector_push_back(Isv, u));+            }+        }+        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;+    }++    /* Create partitions in original graph */+    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);++    /* Create cuts in original graph */+    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++) {+                if (VECTOR(flow)[j] > 0) {+                    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;+}+
+ igraph/src/statusbar.c view
@@ -0,0 +1,130 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2010-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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;+}+
+ igraph/src/structural_properties.c view
@@ -0,0 +1,7238 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "structural_properties_internal.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 shortest path length between all vertex pairs.+ *+ * \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, only those vertex pairs will be included in the calculation+ *        between which there is a path. If \c FALSE, the number of vertices is+ *        used as the distance between vertices unreachable from each other.+ *        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 */+++    if (normfact > 0) {+        *res /= normfact;+    } else {+        *res = IGRAPH_NAN;+    }++    /* 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;+}++/* Not declared static so that the testsuite can use it, but not part of the public API. */+int igraph_rewire_core(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode, igraph_bool_t use_adjlist) {+    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, alledges;+    igraph_bool_t directed, loops, ok;+    igraph_es_t es;+    igraph_adjlist_t al;++    if (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(&eids, 2);++    if (use_adjlist) {+        /* As well as the sorted adjacency list, we maintain an unordered+         * list of edges for picking a random edge in constant time.+         */+        IGRAPH_CHECK(igraph_adjlist_init(graph, &al, IGRAPH_OUT));+        IGRAPH_FINALLY(igraph_adjlist_destroy, &al);+        IGRAPH_VECTOR_INIT_FINALLY(&alledges, no_of_edges * 2);+        igraph_get_edgelist(graph, &alledges, /*bycol=*/ 0);+    } else {+        IGRAPH_VECTOR_INIT_FINALLY(&edgevec, 4);+        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)",+                     num_swaps > 0 ? ((100.0 * num_successful_swaps) / num_swaps) : 0.0);+            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 */+            if (use_adjlist) {+                a = VECTOR(alledges)[((igraph_integer_t)VECTOR(eids)[0]) * 2];+                b = VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[0]) * 2) + 1];+                c = VECTOR(alledges)[((igraph_integer_t)VECTOR(eids)[1]) * 2];+                d = VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[1]) * 2) + 1];+            } else {+                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 (use_adjlist) {+                    /* Flip the edge in the unordered edge-list, so the update later on+                     * hits the correct end. */+                    VECTOR(alledges)[((igraph_integer_t)VECTOR(eids)[1]) * 2] = c;+                    VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[1]) * 2) + 1] = d;+                }+            }++            /* 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) {+                if (use_adjlist) {+                    if (igraph_adjlist_has_edge(&al, a, d, directed)) {+                        ok = 0;+                    }+                } else {+                    IGRAPH_CHECK(igraph_are_connected(graph, a, d, &ok));+                    ok = !ok;+                }+            }+            if (ok) {+                if (use_adjlist) {+                    if (igraph_adjlist_has_edge(&al, c, b, directed)) {+                        ok = 0;+                    }+                } else {+                    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); */+                if (use_adjlist) {+                    // Replace entry in sorted adjlist:+                    IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, a, b, d, directed));+                    IGRAPH_CHECK(igraph_adjlist_replace_edge(&al, c, d, b, directed));+                    // Also replace in unsorted edgelist:+                    VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[0]) * 2) + 1] = d;+                    VECTOR(alledges)[(((igraph_integer_t)VECTOR(eids)[1]) * 2) + 1] = b;+                } else {+                    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++;+    }++    if (use_adjlist) {+        /* Replace graph edges with the adjlist current state */+        IGRAPH_CHECK(igraph_delete_edges(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID)));+        IGRAPH_CHECK(igraph_add_edges(graph, &alledges, 0));+    }++    IGRAPH_PROGRESS("Random rewiring: ", 100.0, 0);++    if (use_adjlist) {+        igraph_vector_destroy(&alledges);+        igraph_adjlist_destroy(&al);+    } else {+        igraph_vector_destroy(&edgevec);+    }++    igraph_vector_destroy(&eids);+    IGRAPH_FINALLY_CLEAN(use_adjlist ? 3 : 2);++    RNG_END();++    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 flags:+ *         \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+ */++#define REWIRE_ADJLIST_THRESHOLD 10++int igraph_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewiring_t mode) {++    igraph_bool_t use_adjlist = n >= REWIRE_ADJLIST_THRESHOLD;+    return igraph_rewire_core(graph, n, mode, use_adjlist);++}++/**+ * 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;+    long int i, j, n;+    long int to;+    igraph_integer_t eid;+    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) {+            IGRAPH_CHECK(igraph_vector_push_back(my_vids_new2old, vid));+            no_of_new_nodes++;+            VECTOR(*my_vids_old2new)[vid] = no_of_new_nodes;+        }+    }++    /* Create the new edge list */+    for (i = 0; i < no_of_new_nodes; i++) {+        long int old_vid = (long int) VECTOR(*my_vids_new2old)[i];+        long int new_vid = i;++        IGRAPH_CHECK(igraph_incident(graph, &nei_edges, old_vid, IGRAPH_OUT));+        n = igraph_vector_size(&nei_edges);++        if (directed) {+            for (j = 0; j < n; j++) {+                eid = (igraph_integer_t) VECTOR(nei_edges)[j];++                to = (long int) VECTOR(*my_vids_old2new)[ (long int)IGRAPH_TO(graph, eid) ];+                if (!to) {+                    continue;+                }++                IGRAPH_CHECK(igraph_vector_push_back(&new_edges, new_vid));+                IGRAPH_CHECK(igraph_vector_push_back(&new_edges, to - 1));+                IGRAPH_CHECK(igraph_vector_push_back(&eids_new2old, eid));+            }+        } else {+            for (j = 0; j < n; j++) {+                eid = (igraph_integer_t) VECTOR(nei_edges)[j];++                if (IGRAPH_FROM(graph, eid) != old_vid) { /* avoid processing edges twice */+                    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, new_vid));+                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 (!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_i_induced_subgraph_suggest_implementation(+    const igraph_t *graph, const igraph_vs_t vids,+    igraph_subgraph_implementation_t *result) {+    double ratio;+    igraph_integer_t num_vs;++    if (igraph_vs_is_all(&vids)) {+        ratio = 1.0;+    } else {+        IGRAPH_CHECK(igraph_vs_size(graph, &vids, &num_vs));+        ratio = (igraph_real_t) num_vs / igraph_vcount(graph);+    }++    /* TODO: needs benchmarking; threshold was chosen totally arbitrarily */+    if (ratio > 0.5) {+        *result = IGRAPH_SUBGRAPH_COPY_AND_DELETE;+    } else {+        *result = IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH;+    }++    return 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) {+        IGRAPH_CHECK(igraph_i_induced_subgraph_suggest_implementation(graph, vids, &impl));+    }++    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_in)[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.+ * \param mindist The minimum distance to include a vertex in the counting.+ *   If this is one, then the starting vertex is not counted. If this is+ *   two, then its neighbors are not counted, either, etc.+ * \return Error code.+ *+ * \sa \ref igraph_neighborhood() for calculating the actual neighborhood,+ * \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,+                             igraph_integer_t mindist) {++    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);+    }++    if (mindist < 0 || mindist > order) {+        IGRAPH_ERROR("Minimum distance should be between zero and order",+                     IGRAPH_EINVAL);+    }++    added = igraph_Calloc(no_of_nodes, long int);+    if (added == 0) {+        IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);+    }+    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 = mindist == 0 ? 1 : 0;+        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));+                        if (actdist + 1 >= mindist) {+                            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;+                        if (actdist + 1 >= mindist) {+                            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.+ * \param mindist The minimum distance to include a vertex in the counting.+ *   If this is one, then the starting vertex is not counted. If this is+ *   two, then its neighbors are not counted, either, etc.+ * \return Error code.+ *+ * \sa \ref igraph_neighborhood_size() to calculate the size of the+ * 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, igraph_integer_t mindist) {++    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);+    }++    if (mindist < 0 || mindist > order) {+        IGRAPH_ERROR("Minimum distance should be between zero and order",+                     IGRAPH_EINVAL);+    }++    added = igraph_Calloc(no_of_nodes, long int);+    if (added == 0) {+        IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);+    }+    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);+        if (mindist == 0) {+            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));+                        if (actdist + 1 >= mindist) {+                            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;+                        if (actdist + 1 >= mindist) {+                            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.+ * \param mindist The minimum distance to include a vertex in the counting.+ *   If this is one, then the starting vertex is not counted. If this is+ *   two, then its neighbors are not counted, either, etc.+ * \return Error code.+ *+ * \sa \ref igraph_neighborhood_size() for calculating the neighborhood+ * 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,+                               igraph_integer_t mindist) {+    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);+    }++    if (mindist < 0 || mindist > order) {+        IGRAPH_ERROR("Minimum distance should be between zero and order",+                     IGRAPH_EINVAL);+    }++    added = igraph_Calloc(no_of_nodes, long int);+    if (added == 0) {+        IGRAPH_ERROR("Cannot calculate neighborhood size", IGRAPH_ENOMEM);+    }+    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);+        if (mindist == 0) {+            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));+                        if (actdist + 1 >= mindist) {+                            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;+                        if (actdist + 1 >= mindist) {+                            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_has_loop+ * \brief Returns whether the graph has at least one loop edge.+ *+ * </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.+ *+ * \sa \ref igraph_simplify() to get rid of loop edges.+ *+ * Time complexity: O(e), the number of edges to check.+ *+ * \example examples/simple/igraph_has_loop.c+ */++int igraph_has_loop(const igraph_t *graph, igraph_bool_t *res) {+    long int i, m = igraph_ecount(graph);++    *res = 0;++    for (i = 0; i < m; i++) {+        if (IGRAPH_FROM(graph, i) == IGRAPH_TO(graph, i)) {+            *res = 1;+            break;+        }+    }++    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_int_t *eids;+    igraph_vector_t *ins_p, *outs_p, ins_v, outs_v;+    igraph_dqueue_t q;+    igraph_inclist_t inclist;+    igraph_bool_t directed = igraph_is_directed(graph);++    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_int_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);+            long int size, act, edge;+            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();++            size = 0;+            act = node;+            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);+    long int no_of_roots = igraph_vector_size(roots);+    long int tree_vertex_count = no_of_nodes;++    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 i, n, r, v_ptr = no_of_nodes;++    /* TODO: handle not-connected graphs, multiple root vertices */++    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);+    igraph_vector_reserve(&edges, no_of_edges * 2);+    IGRAPH_DQUEUE_INIT_FINALLY(&Q, 100);+    IGRAPH_VECTOR_INIT_FINALLY(&neis, 0);+    IGRAPH_VECTOR_BOOL_INIT_FINALLY(&seen_vertices, no_of_nodes);+    IGRAPH_VECTOR_BOOL_INIT_FINALLY(&seen_edges, no_of_edges);++    if (vertex_index) {+        IGRAPH_CHECK(igraph_vector_resize(vertex_index, no_of_nodes));+        for (i = 0; i < no_of_nodes; i++) {+            VECTOR(*vertex_index)[i] = i;+        }+    }++    for (r = 0; r < no_of_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);++            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]) {++                        igraph_vector_push_back(&edges, from);+                        igraph_vector_push_back(&edges, to);++                        VECTOR(seen_vertices)[nei] = 1;+                        IGRAPH_CHECK(igraph_dqueue_push(&Q, nei));++                    } else {++                        tree_vertex_count++;+                        if (vertex_index) {+                            IGRAPH_CHECK(igraph_vector_push_back(vertex_index, nei));+                        }++                        if (from == nei) {+                            igraph_vector_push_back(&edges, v_ptr++);+                            igraph_vector_push_back(&edges, to);+                        } else {+                            igraph_vector_push_back(&edges, from);+                            igraph_vector_push_back(&edges, 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, tree_vertex_count, 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_neimode_t mode,+        igraph_neimode_t neighbor_degree_mode,+        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_neimode_t mode,+        igraph_neimode_t neighbor_degree_mode,+        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, edge_neis;+    long int i, j, no_vids;+    igraph_vit_t vit;+    igraph_vector_t my_knn_v, *my_knn = knn;+    igraph_vector_t strength, deg;+    igraph_integer_t maxdeg;+    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));+    }++    // Get degree of neighbours+    IGRAPH_VECTOR_INIT_FINALLY(&deg, no_of_nodes);+    IGRAPH_CHECK(igraph_degree(graph, &deg, igraph_vss_all(),+                               neighbor_degree_mode, IGRAPH_LOOPS));+    IGRAPH_VECTOR_INIT_FINALLY(&strength, no_of_nodes);++    // Get strength of all nodes+    IGRAPH_CHECK(igraph_strength(graph, &strength, igraph_vss_all(),+                                 mode, IGRAPH_LOOPS, weights));++    // Get maximum degree for initialization+    IGRAPH_CHECK(igraph_maxdegree(graph, &maxdeg, igraph_vss_all(),+                                  mode, IGRAPH_LOOPS));+    IGRAPH_VECTOR_INIT_FINALLY(&neis, (long int)maxdeg);+    IGRAPH_VECTOR_INIT_FINALLY(&edge_neis, (long int)maxdeg);+    igraph_vector_resize(&neis, 0);+    igraph_vector_resize(&edge_neis, 0);++    if (knnk) {+        IGRAPH_CHECK(igraph_vector_resize(knnk, (long int)maxdeg));+        igraph_vector_null(knnk);+        IGRAPH_VECTOR_INIT_FINALLY(&deghist, (long int)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(strength)[v];+        // Get neighbours and incident edges+        IGRAPH_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, mode));+        IGRAPH_CHECK(igraph_incident(graph, &edge_neis, (igraph_integer_t) v, mode));+        nv = igraph_vector_size(&neis);+        for (j = 0; j < nv; j++) {+            long int nei = (long int) VECTOR(neis)[j];+            long int e = (long int) VECTOR(edge_neis)[j];+            double w = VECTOR(*weights)[e];+            sum += w * 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] /= dh;+            } 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 mode The neighbors over which is averaged.+ * \param neighbor_degree_mode The degree of the neighbors which is+ *   averaged.+ * \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. The weighted version computes+ *   a weighted average of the neighbor degrees, i.e.+ *+ *    k_nn_i = 1/s_i sum_j w_ij k_j+ *+ *   where s_i is the sum of the weights, the sum runs over+ *   the neighbors as indicated by \c mode (with appropriate weights)+ *   and k_j is the degree, specified by \c neighbor_degree_mode.+ * \return Error code.+ *+ * Time complexity: O(|V|+|E|), linear in the number of vertices and+ * edges.+ *+ * \example examples/simple/igraph_knn.c+ */++int igraph_avg_nearest_neighbor_degree(const igraph_t *graph,+                                       igraph_vs_t vids,+                                       igraph_neimode_t mode,+                                       igraph_neimode_t neighbor_degree_mode,+                                       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;+    igraph_integer_t 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,+                mode, neighbor_degree_mode, 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(),+                               neighbor_degree_mode, IGRAPH_LOOPS));+    igraph_maxdegree(graph, &maxdeg, igraph_vss_all(), mode, IGRAPH_LOOPS);+    IGRAPH_VECTOR_INIT_FINALLY(&neis, maxdeg);+    igraph_vector_resize(&neis, 0);++    if (knnk) {+        IGRAPH_CHECK(igraph_vector_resize(knnk, (long int)maxdeg));+        igraph_vector_null(knnk);+        IGRAPH_VECTOR_INIT_FINALLY(&deghist, (long int)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_CHECK(igraph_neighbors(graph, &neis, (igraph_integer_t) v, mode));+        nv = igraph_vector_size(&neis);+        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] /= dh;+            } 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) {++    /* 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 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_inclist_t inclist;+    long int source, j;+    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));+        if (pres) {+            *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_2wheap_init(&Q, no_of_nodes));+    IGRAPH_FINALLY(igraph_2wheap_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_2wheap_clear(&Q);+        igraph_2wheap_push_with_index(&Q, source, -1.0);++        nodes_reached = 0.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_int_t *neis;+            long int nlen;++            if (mindist > res) {+                res = mindist; from = source; to = minnei;+            }+            nodes_reached++;++            /* Now check all neighbors of 'minnei' for a shorter path */+            neis = igraph_inclist_get(&inclist, minnei);+            nlen = igraph_vector_int_size(neis);+            for (j = 0; j < nlen; j++) {+                long int edge = (long int) VECTOR(*neis)[j];+                long int tto = IGRAPH_OTHER(graph, edge, minnei);+                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) {+                    /* First finite distance */+                    IGRAPH_CHECK(igraph_2wheap_push_with_index(&Q, tto, -altdist));+                } else if (altdist < curdist) {+                    /* A shorter path */+                    IGRAPH_CHECK(igraph_2wheap_modify(&Q, tto, -altdist));+                }+            }++        } /* !igraph_2wheap_empty(&Q) */++        /* not connected, return infinity */+        if (nodes_reached != no_of_nodes && !unconn) {+            res = IGRAPH_INFINITY;+            from = to = -1;+            break;+        }++    } /* source < no_of_nodes */++    /* Compensate for the +1 that we have added to distances */+    res -= 1;++    igraph_inclist_destroy(&inclist);+    igraph_2wheap_destroy(&Q);+    IGRAPH_FINALLY_CLEAN(2);++    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.+ *+ * </para><para>+ * Z Kiraly: Recognizing graphic degree sequences and generating all+ * realizations. TR-2011-11, Egervary Research Group, H-1117, Budapest,+ * Hungary. ISSN 1587-4451, 2012.+ *+ * \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 log n) for undirected graphs, O(n^2) for directed+ *                  graphs, 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;+    long int w, b, s, c, n, k;++    IGRAPH_CHECK(igraph_vector_copy(&work, degrees));+    IGRAPH_FINALLY(igraph_vector_destroy, &work);++    igraph_vector_sort(&work);++    /* This algorithm is outlined in TR-2011-11 of the Egervary Research Group,+     * ISSN 1587-4451. The main loop of the algorithm is O(n) but it is dominated+     * by an O(n log n) quicksort; this could in theory be brought down to+     * O(n) with binsort but it's probably not worth the fuss.+     *+     * Variables names are mostly according to the technical report, apart from+     * the degrees themselves. w and k are zero-based here; in the technical+     * report they are 1-based */+    *res = 1;+    n = igraph_vector_size(&work);+    w = n - 1; b = 0; s = 0; c = 0;+    for (k = 0; k < n; k++) {+        b += VECTOR(*degrees)[k];+        c += w;+        while (w > k && VECTOR(*degrees)[w] <= k + 1) {+            s += VECTOR(*degrees)[w];+            c -= (k + 1);+            w--;+        }+        if (b > c + s) {+            *res = 0;+            break;+        }+        if (w == k) {+            break;+        }+    }++    igraph_vector_destroy(&work);+    IGRAPH_FINALLY_CLEAN(1);++    return 0;+}++typedef struct {+    const igraph_vector_t* first;+    const igraph_vector_t* second;+} igraph_i_qsort_dual_vector_cmp_data_t;++int igraph_i_qsort_dual_vector_cmp_desc(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_long_t index_array;+    long int i, j, vcount, lhs, rhs;+    igraph_i_qsort_dual_vector_cmp_data_t sort_data;++    /* Create an index vector that sorts the vertices by decreasing in-degree */+    vcount = igraph_vector_size(out_degrees);+    IGRAPH_CHECK(igraph_vector_long_init_seq(&index_array, 0, vcount - 1));+    IGRAPH_FINALLY(igraph_vector_long_destroy, &index_array);++    /* Set up the auxiliary struct for sorting */+    sort_data.first  = in_degrees;+    sort_data.second = out_degrees;++    /* Sort the index vector */+    igraph_qsort_r(VECTOR(index_array), vcount, sizeof(long int), &sort_data,+                   igraph_i_qsort_dual_vector_cmp_desc);++    /* Be optimistic, then check whether the Fulkerson–Chen–Anstee condition+     * holds for every k. In particular, for every k in [0; n), it must be true+     * that:+     *+     * \sum_{i=0}^k indegree[i] <=+     *     \sum_{i=0}^k min(outdegree[i], k) ++     *     \sum_{i=k+1}^{n-1} min(outdegree[i], k + 1)+     */++#define INDEGREE(x) (VECTOR(*in_degrees)[VECTOR(index_array)[x]])+#define OUTDEGREE(x) (VECTOR(*out_degrees)[VECTOR(index_array)[x]])++    *res = 1;+    lhs = 0;+    for (i = 0; i < vcount; i++) {+        lhs += INDEGREE(i);++        /* It is enough to check for indexes where the in-degree is about to+         * decrease in the next step; see "Stronger condition" in the Wikipedia+         * entry for the Fulkerson-Chen-Anstee condition */+        if (i != vcount - 1 && INDEGREE(i) == INDEGREE(i + 1)) {+            continue;+        }++        rhs = 0;+        for (j = 0; j <= i; j++) {+            rhs += OUTDEGREE(j) < i ? OUTDEGREE(j) : i;+        }+        for (j = i + 1; j < vcount; j++) {+            rhs += OUTDEGREE(j) < (i + 1) ? OUTDEGREE(j) : (i + 1);+        }++        if (lhs > rhs) {+            *res = 0;+            break;+        }+    }++#undef INDEGREE+#undef OUTDEGREE++    igraph_vector_long_destroy(&index_array);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}++#undef SUCCEED+#undef FAIL+++/* igraph_is_tree -- check if a graph is a tree */++/* count the number of vertices reachable from the root */+static int igraph_i_is_tree_visitor(igraph_integer_t root, const igraph_adjlist_t *al, igraph_integer_t *visited_count) {+    igraph_stack_int_t stack;+    igraph_vector_bool_t visited;+    long i;++    IGRAPH_CHECK(igraph_vector_bool_init(&visited, igraph_adjlist_size(al)));+    IGRAPH_FINALLY(igraph_vector_bool_destroy, &visited);++    IGRAPH_CHECK(igraph_stack_int_init(&stack, 0));+    IGRAPH_FINALLY(igraph_stack_int_destroy, &stack);++    *visited_count = 0;++    /* push the root into the stack */+    IGRAPH_CHECK(igraph_stack_int_push(&stack, root));++    while (! igraph_stack_int_empty(&stack)) {+        igraph_integer_t u;+        igraph_vector_int_t *neighbors;+        long ncount;++        /* take a vertex from the stack, mark it as visited */+        u = igraph_stack_int_pop(&stack);+        if (IGRAPH_LIKELY(! VECTOR(visited)[u])) {+            VECTOR(visited)[u] = 1;+            *visited_count += 1;+        }++        /* register all its yet-unvisited neighbours for future processing */+        neighbors = igraph_adjlist_get(al, u);+        ncount = igraph_vector_int_size(neighbors);+        for (i = 0; i < ncount; ++i) {+            igraph_integer_t v = VECTOR(*neighbors)[i];+            if (! VECTOR(visited)[v]) {+                IGRAPH_CHECK(igraph_stack_int_push(&stack, v));+            }+        }+    }++    igraph_stack_int_destroy(&stack);+    igraph_vector_bool_destroy(&visited);+    IGRAPH_FINALLY_CLEAN(2);++    return IGRAPH_SUCCESS;+}+++/**+ * \ingroup structural+ * \function igraph_is_tree+ * \brief Decides whether the graph is a tree.+ *+ * An undirected graph is a tree if it is connected and has no cycles.+ * </para><para>+ *+ * In the directed case, a possible additional requirement is that all+ * edges are oriented away from a root (out-tree or arborescence) or all edges+ * are oriented towards a root (in-tree or anti-arborescence).+ * This test can be controlled using the \p mode parameter.+ * </para><para>+ *+ * By convention, the null graph (i.e. the graph with no vertices) is considered not to be a tree.+ *+ * \param graph The graph object to analyze.+ * \param res Pointer to a logical variable, the result will be stored+ *        here.+ * \param root If not \c NULL, the root node will be stored here. When \p mode+ *        is \c IGRAPH_ALL or the graph is undirected, any vertex can be the root+ *        and \p root is set to 0 (the first vertex). When \p mode is \c IGRAPH_OUT+ *        or \c IGRAPH_IN, the root is set to the vertex with zero in- or out-degree,+ *        respectively.+ * \param mode For a directed graph this specifies whether to test for an+ *        out-tree, an in-tree or ignore edge directions. The respective+ *        possible values are:+ *        \c IGRAPH_OUT, \c IGRAPH_IN, \c IGRAPH_ALL. This argument is+ *        ignored for undirected graphs.+ * \return Error code:+ *        \c IGRAPH_EINVAL: invalid mode argument.+ *+ * Time complexity: At most O(|V|+|E|), the+ * number of vertices plus the number of edges in the graph.+ *+ * \sa igraph_is_weakly_connected()+ *+ * \example examples/simple/igraph_tree.c+ */++int igraph_is_tree(const igraph_t *graph, igraph_bool_t *res, igraph_integer_t *root, igraph_neimode_t mode) {+    igraph_adjlist_t al;+    igraph_integer_t iroot = 0;+    igraph_integer_t visited_count;+    igraph_integer_t vcount, ecount;++    vcount = igraph_vcount(graph);+    ecount = igraph_ecount(graph);++    /* A tree must have precisely vcount-1 edges. */+    /* By convention, the zero-vertex graph will not be considered a tree. */+    if (ecount != vcount - 1) {+        *res = 0;+        return IGRAPH_SUCCESS;+    }++    /* The single-vertex graph is a tree, provided it has no edges (checked in the previous if (..)) */+    if (vcount == 1) {+        *res = 1;+        if (root) {+            *root = 0;+        }+        return IGRAPH_SUCCESS;+    }++    /* For higher vertex counts we cannot short-circuit due to the possibility+     * of loops or multi-edges even when the edge count is correct. */++    /* Ignore mode for undirected graphs. */+    if (! igraph_is_directed(graph)) {+        mode = IGRAPH_ALL;+    }++    IGRAPH_CHECK(igraph_adjlist_init(graph, &al, mode));+    IGRAPH_FINALLY(igraph_adjlist_destroy, &al);++    /* The main algorithm:+     * We find a root and check that all other vertices are reachable from it.+     * We have already checked the number of edges, so with the additional+     * reachability condition we can verify if the graph is a tree.+     *+     * For directed graphs, the root is the node with no incoming/outgoing+     * connections, depending on 'mode'. For undirected, it is arbitrary, so+     * we choose 0.+     */++    *res = 1; /* assume success */++    switch (mode) {+    case IGRAPH_ALL:+        iroot = 0;+        break;++    case IGRAPH_IN:+    case IGRAPH_OUT: {+        igraph_vector_t degree;+        igraph_integer_t i;++        IGRAPH_CHECK(igraph_vector_init(&degree, 0));+        IGRAPH_FINALLY(igraph_vector_destroy, &degree);++        IGRAPH_CHECK(igraph_degree(graph, &degree, igraph_vss_all(), mode == IGRAPH_IN ? IGRAPH_OUT : IGRAPH_IN, /* loops = */ 1));++        for (i = 0; i < vcount; ++i)+            if (VECTOR(degree)[i] == 0) {+                break;+            }++        /* if no suitable root is found, the graph is not a tree */+        if (i == vcount) {+            *res = 0;+        } else {+            iroot = i;+        }++        igraph_vector_destroy(&degree);+        IGRAPH_FINALLY_CLEAN(1);+    }++    break;+    default:+        IGRAPH_ERROR("Invalid mode", IGRAPH_EINVMODE);+    }++    /* if no suitable root was found, skip visting vertices */+    if (*res) {+        IGRAPH_CHECK(igraph_i_is_tree_visitor(iroot, &al, &visited_count));+        *res = visited_count == vcount;+    }++    if (root) {+        *root = iroot;+    }++    igraph_adjlist_destroy(&al);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}
+ igraph/src/structure_generators.c view
@@ -0,0 +1,2443 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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_structural.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_bool_t has_edges = igraph_vector_size(edges) > 0;+    igraph_real_t max = has_edges ? igraph_vector_max(edges) + 1 : 0;++    if (igraph_vector_size(edges) % 2 != 0) {+        IGRAPH_ERROR("Invalid (odd) edges vector", IGRAPH_EINVEVECTOR);+    }+    if (has_edges && !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 (has_edges) {+        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; \ref igraph_from_prufer() for creating arbitrary trees;+ * \ref igraph_tree_game() for uniform random sampling of trees.+ *+ * \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, n, 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&lt;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 cycle graph with additional chords+ * connecting its vertices.+ *+ * Each row \c L of the matrix \p W specifies a set of chords to be+ * inserted, in the following way: vertex \c i will connect to a vertex+ * <code>L[(i mod p)]</code> steps ahead of it along the cycle, where+ * \c p is the length of \c L.+ * In other words, vertex \c i will be connected to vertex+ * <code>(i + L[(i mod p)]) mod nodes</code>.+ *+ * </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.+ * \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.+ * \param directed Whether the graph should be directed.+ * \return Error code.+ *+ * \sa \ref igraph_ring(), \ref igraph_lcf(), \ref igraph_lcf_vector()+ *+ * 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_bool_t directed) {+    igraph_vector_t edges;+    long int period = igraph_matrix_ncol(W);+    long int nrow   = igraph_matrix_nrow(W);+    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, 2 * (nodes + nodes * nrow));++    for (i = 0; i < nodes - 1; i++) {+        VECTOR(edges)[epos++] = i;+        VECTOR(edges)[epos++] = i + 1;+    }+    VECTOR(edges)[epos++] = nodes - 1;+    VECTOR(edges)[epos++] = 0;++    if (nrow > 0) {+        for (i = 0; i < nodes; i++) {+            for (j = 0; j < nrow; j++) {+                long int offset = (long int) MATRIX(*W, j, mpos);+                long int v = (i + offset) % nodes;++                if (v < 0) {+                    v += nodes;    /* handle negative offsets */+                }++                VECTOR(edges)[epos++] = i;+                VECTOR(edges)[epos++] = v;++            }+            mpos++; if (mpos == period) {+                mpos = 0;+            }+        }+    }++    IGRAPH_CHECK(igraph_create(graph, &edges, nodes, directed));+    igraph_vector_destroy(&edges);+    IGRAPH_FINALLY_CLEAN(1);+    return IGRAPH_SUCCESS;+}++/**+ * \function igraph_connect_neighborhood+ * \brief Connects every vertex to its neighborhood+ *+ * This function adds new edges to the input graph. Each vertex is connected+ * to all vertices reachable by at most \p order steps from it+ * (unless a connection already existed).  In other words, the \p order power of+ * the graph is computed.+ *+ * </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^k), |V| is the number of vertices in the+ * graph, d is the average degree and k 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(), \ref igraph_extended_chordal_ring()+ *+ * 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;++    if (repeats < 0) {+        IGRAPH_ERROR("number of repeats must be positive", IGRAPH_EINVAL);+    }+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * no_of_edges);++    if (no_of_nodes > 0) {+        /* 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;+        VECTOR(edges)[ptr++] = from;+        VECTOR(edges)[ptr++] = to;+        sptr++;+    }++    IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) no_of_nodes,+                               IGRAPH_UNDIRECTED));+    IGRAPH_CHECK(igraph_simplify(graph, 1 /* true */, 1 /* true */, NULL));+    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;+}+++/**+ * \ingroup generators+ * \function igraph_from_prufer+ * \brief Generates a tree from a Pr&uuml;fer sequence+ *+ * A Pr&uuml;fer sequence is a unique sequence of integers associated+ * with a labelled tree. A tree on n vertices can be represented by a+ * sequence of n-2 integers, each between 0 and n-1 (inclusive).+ *+ * The algorithm used by this function is based on+ * Paulius Micikevi&ccaron;ius, Saverio Caminiti, Narsingh Deo:+ * Linear-time Algorithms for Encoding Trees as Sequences of Node Labels+ *+ * \param graph Pointer to an uninitialized graph object.+ * \param prufer The Pr&uuml;fer sequence+ * \return Error code:+ *          \clist+ *          \cli IGRAPH_ENOMEM+ *             there is not enough memory to perform the operation.+ *          \cli IGRAPH_EINVAL+ *             invalid Pr&uuml;fer sequence given+ *          \endclist+ *+ * \sa \ref igraph_tree(), \ref igraph_tree_game()+ *+ */++int igraph_from_prufer(igraph_t *graph, const igraph_vector_int_t *prufer) {+    igraph_vector_int_t degree;+    igraph_vector_t edges;+    long n;+    long i, k;+    long u, v; /* vertices */+    long ec;++    n = igraph_vector_int_size(prufer) + 2;++    IGRAPH_VECTOR_INT_INIT_FINALLY(&degree, n); /* initializes vector to zeros */+    IGRAPH_VECTOR_INIT_FINALLY(&edges, 2 * (n - 1));++    /* build out-degree vector (i.e. number of child vertices) and verify Prufer sequence */+    for (i = 0; i < n - 2; ++i) {+        long u = VECTOR(*prufer)[i];+        if (u >= n || u < 0) {+            IGRAPH_ERROR("Invalid Prufer sequence", IGRAPH_EINVAL);+        }+        VECTOR(degree)[u] += 1;+    }++    v = 0;  /* initialize v now, in case Prufer sequence is empty */+    k = 0;  /* index into the Prufer vector */+    ec = 0; /* index into the edges vector */+    for (i = 0; i < n; ++i) {+        u = i;++        while (k < n - 2 && u <= i && (VECTOR(degree)[u] == 0)) {+            /* u is a leaf here */++            v = VECTOR(*prufer)[k]; /* parent of u */++            /* add edge */+            VECTOR(edges)[ec++] = v;+            VECTOR(edges)[ec++] = u;++            k += 1;++            VECTOR(degree)[v] -= 1;++            u = v;+        }++        if (k == n - 2) {+            break;+        }+    }++    /* find u for last edge, v is already set */+    for (u = i + 1; u < n; ++u)+        if ((VECTOR(degree)[u] == 0) && u != v) {+            break;+        }++    /* add last edge */+    VECTOR(edges)[ec++] = v;+    VECTOR(edges)[ec++] = u;++    IGRAPH_CHECK(igraph_create(graph, &edges, (igraph_integer_t) n, /* directed = */ 0));++    igraph_vector_destroy(&edges);+    igraph_vector_int_destroy(&degree);+    IGRAPH_FINALLY_CLEAN(2);++    return IGRAPH_SUCCESS;+}
+ igraph/src/sue.c view
@@ -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
+ igraph/src/sugiyama.c view
@@ -0,0 +1,1340 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   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++
+ igraph/src/system_.c view
@@ -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
+ igraph/src/topology.c view
@@ -0,0 +1,3129 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "igraph_structural.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().</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 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);+    igraph_bool_t loop1, loop2;++    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_CHECK(igraph_has_loop(graph1, &loop1));+        IGRAPH_CHECK(igraph_has_loop(graph2, &loop2));+        if (!loop1 && !loop2) {+            IGRAPH_CHECK(igraph_isomorphic_34(graph1, graph2, iso));+        } else {+            IGRAPH_CHECK(igraph_isomorphic_bliss(graph1, graph2, NULL, NULL, iso,+                                                 0, 0, /*sh=*/ IGRAPH_BLISS_F, 0, 0));+        }+    } else {+        IGRAPH_CHECK(igraph_isomorphic_bliss(graph1, graph2, NULL, NULL, iso,+                                             0, 0, /*sh=*/ IGRAPH_BLISS_F, 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;+}++/**+ * \section about_vf2+ *+ * <para>+ * The VF2 algorithm can search for a subgraph in a larger graph, or check if two+ * graphs are isomorphic. 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>+ * VF2 supports both vertex and edge-colored graphs, as well as custom vertex or edge+ * compatibility functions.+ * </para>+ *+ * <para>+ * VF2 works with both directed and undirected graphs. Only simple graphs are supported.+ * Self-loops or multi-edges must not be present in the graphs. Currently, the VF2+ * functions do not check that the input graph is simple: it is the responsibility+ * of the user to pass in valid input.+ * </para>+ */++/**+ * \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. The callback function must not destroy the+ * mapping vectors that are passed to it.+ * \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 (no_of_nodes != igraph_vcount(graph2) ||+        no_of_edges != igraph_ecount(graph2)) {+        return 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);+        }+    }++    /* 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 structures 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. For more information,+ * see the BLISS homepage at http://www.tcs.hut.fi/Software/bliss/ and the publication+ * Tommi Junttila, Petteri Kaski: "Engineering an Efficient Canonical Labeling+ * Tool for Large and Sparse Graphs" at https://doi.org/10.1137/1.9781611972870.13+ * </para>+ *+ * <para>+ * BLISS works with both directed graphs and undirected graphs. It supports graphs with+ * self-loops, but not graphs with multi-edges.+ * </para>+ *+ * <para>+ * BLISS version 0.73 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.73 version of BLISS is included in igraph.+ *+ * </para><para>+ *+ * \param graph1 The first input graph. Multiple edges between the same nodes+ *   are not supported and will cause an incorrect result to be returned.+ * \param graph2 The second input graph. Multiple edges between the same nodes+ *   are not supported and will cause an incorrect result to be returned.+ * \param colors1 An optional vertex color vector for the first graph. Supply a+ *   null pointer if your graph is not colored.+ * \param colors2 An optional vertex color vector for the second graph. Supply a+ *   null pointer if your graph is not colored.+ * \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 sh Splitting heuristics to be used for the graphs. 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,+                            const igraph_vector_int_t *colors1, const igraph_vector_int_t *colors2,+                            igraph_bool_t *iso, igraph_vector_t *map12,+                            igraph_vector_t *map21, igraph_bliss_sh_t sh,+                            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;+    igraph_bool_t directed;+    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 = info1->nof_generators = -1;+        info1->group_size = 0;+    }+    if (info2) {+        info2->nof_nodes = info2->nof_leaf_nodes = info2->nof_bad_nodes =+                               info2->nof_canupdates = info2->max_level = info2->nof_generators = -1;+        info2->group_size = 0;+    }++    directed = igraph_is_directed(graph1);+    if (igraph_is_directed(graph2) != directed) {+        IGRAPH_ERROR("Cannot compare directed and undirected graphs",+                     IGRAPH_EINVAL);+    }+    if ((colors1 == NULL || colors2 == NULL) && colors1 != colors2) {+        IGRAPH_WARNING("Only one of the graphs is vertex colored, colors will be ignored");+        colors1 = NULL; colors2 = NULL;+    }++    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, colors1, &perm1, sh, info1));+    IGRAPH_CHECK(igraph_canonical_permutation(graph2, colors2, &perm2, sh, 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 (! directed && 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 (! directed && 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;+        }+    }++    /* If the graphs are coloured, we also need to check that applying the+       permutation mymap12 to colors1 gives colors2. */++    if (*iso && colors1 != NULL) {+        for (i = 0; i < no_of_nodes; i++) {+            if (VECTOR(*colors1)[i] != VECTOR(*colors2)[(long int) VECTOR(*mymap12)[i] ]) {+                *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;+}+++/**+ * \function igraph_simplify_and_colorize+ * \brief Simplify the graph and compute self-loop and edge multiplicities.+ *+ * </para><para>+ * This function creates a vertex and edge colored simple graph from the input+ * graph. The vertex colors are computed as the number of incident self-loops+ * to each vertex in the input graph. The edge colors are computed as the number of+ * parallel edges in the input graph that were merged to create each edge+ * in the simple graph.+ *+ * </para><para>+ * The resulting colored simple graph is suitable for use by isomorphism checking+ * algorithms such as VF2, which only support simple graphs, but can consider+ * vertex and edge colors.+ *+ * \param graph The graph object, typically having self-loops or multi-edges.+ * \param res An uninitialized graph object. The result will be stored here+ * \param vertex_color Computed vertex colors corresponding to self-loop multiplicities.+ * \param edge_color Computed edge colors corresponding to edge multiplicities+ * \return Error code.+ *+ * \sa \ref igraph_simplify(), \ref igraph_isomorphic_vf2(), \ref igraph_subisomorphic_vf2()+ *+ */+int igraph_simplify_and_colorize(+    const igraph_t *graph, igraph_t *res,+    igraph_vector_int_t *vertex_color, igraph_vector_int_t *edge_color) {+    igraph_es_t es;+    igraph_eit_t eit;+    igraph_vector_t edges;+    long int no_of_nodes = igraph_vcount(graph);+    long int no_of_edges = igraph_ecount(graph);+    long int pto = -1, pfrom = -1;+    long int i;++    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);++    IGRAPH_VECTOR_INIT_FINALLY(&edges, 0);+    IGRAPH_CHECK(igraph_vector_reserve(&edges, no_of_edges * 2));++    IGRAPH_CHECK(igraph_vector_int_resize(vertex_color, no_of_nodes));+    igraph_vector_int_null(vertex_color);++    IGRAPH_CHECK(igraph_vector_int_resize(edge_color, no_of_edges));+    igraph_vector_int_null(edge_color);++    i = -1;+    for (; !IGRAPH_EIT_END(eit); 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);++        if (to == from) {+            VECTOR(*vertex_color)[to]++;+            continue;+        }++        if (to == pto && from == pfrom) {+            VECTOR(*edge_color)[i]++;+        } else {+            igraph_vector_push_back(&edges, from);+            igraph_vector_push_back(&edges, to);+            i++;+            VECTOR(*edge_color)[i] = 1;+        }++        pfrom = from; pto = to;+    }++    igraph_vector_int_resize(edge_color, i + 1);++    igraph_eit_destroy(&eit);+    igraph_es_destroy(&es);+    IGRAPH_FINALLY_CLEAN(2);++    IGRAPH_CHECK(igraph_create(res, &edges, no_of_nodes, igraph_is_directed(graph)));++    igraph_vector_destroy(&edges);+    IGRAPH_FINALLY_CLEAN(1);++    return IGRAPH_SUCCESS;+}
+ igraph/src/triangles.c view
@@ -0,0 +1,978 @@+/* -*- mode: C -*-  */+/* vim:set ts=4 sw=4 sts=4 et: */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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"+#include "igraph_structural.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;+    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);+        /* 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 (neilen1 >= 2) {+            sum += VECTOR(triangles)[node] / neilen1 / (neilen1 - 1) * 2.0;+            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 TRANSIT+#include "triangles_template1.h"+#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);+        if (mode == IGRAPH_TRANSITIVITY_ZERO && deg < 2) {+            VECTOR(*res)[i] = 0.0;+        } else {+            VECTOR(*res)[i] = VECTOR(triangles)[idx] / deg / (deg - 1) * 2.0;+        }+        /*     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 TRANSIT 1+#include "triangles_template.h"+#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, which should be undirected and simple.+ * \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) {++    igraph_bool_t simple;++    if (igraph_is_directed(graph)) {+        IGRAPH_ERROR("Transitivity works on undirected graphs only", IGRAPH_EINVAL);+    }++    igraph_is_simple(graph, &simple);+    if (!simple) {+        IGRAPH_ERROR("Transitivity works on simple graphs only", IGRAPH_EINVAL);+    }++    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;+}++/**+ * \function igraph_adjacent_triangles+ * Count the number of triangles a vertex is part of+ *+ * \param graph The input graph. Edge directions are ignored.+ * \param res Initiliazed vector, the results are stored here.+ * \param vids The vertices to perform the calculation for.+ * \return Error mode.+ *+ * \sa \ref igraph_list_triangles() to list them.+ *+ * Time complexity: O(d^2 n), d is the average vertex degree of the+ * queried vertices, n is their number.+ */++int igraph_adjacent_triangles(const igraph_t *graph,+                              igraph_vector_t *res,+                              const igraph_vs_t vids) {+    if (igraph_vs_is_all(&vids)) {+        return igraph_adjacent_triangles4(graph, res);+    } else {+        return igraph_adjacent_triangles1(graph, res, vids);+    }++    return 0;++}++/**+ * \function igraph_list_triangles+ * Find all triangles in a graph+ *+ * \param graph The input graph, edge directions are ignored.+ * \param res Pointer to an initialized integer vector, the result+ *        is stored here, in a long list of triples of vertex ids.+ *        Each triple is a triangle in the graph. Each triangle is+ *        listed exactly once.+ * \return Error code.+ *+ * \sa \ref igraph_transitivity_undirected() to count the triangles,+ * \ref igraph_adjacent_triangles() to count the triangles a vertex+ * participates in.+ *+ * Time complexity: O(d^2 n), d is the average degree, n is the number+ * of vertices.+ */++int igraph_list_triangles(const igraph_t *graph,+                          igraph_vector_int_t *res) {+# define TRIANGLES+# include "triangles_template.h"+# undef TRIANGLES+    return 0;+}++/**+ * \ingroup structural+ * \function igraph_transitivity_undirected+ * \brief Calculates the transitivity (clustering coefficient) of a graph.+ *+ * </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_int_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_int_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_int_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;+}
+ igraph/src/type_indexededgelist.c view
@@ -0,0 +1,1706 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2005-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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.+ *+ * Time complexity: operating system specific.+ */+void 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);+}++/**+ * \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) {++    if (igraph_is_directed(graph)) {+        *from = (igraph_integer_t) VECTOR(graph->from)[(long int)eid];+        *to   = (igraph_integer_t) VECTOR(graph->to  )[(long int)eid];+    } else {+        *from = (igraph_integer_t) VECTOR(graph->to  )[(long int)eid];+        *to   = (igraph_integer_t) VECTOR(graph->from)[(long int)eid];+    }++    return 0;+}++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));+    if (igraph_is_directed(graph)) {+        for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {+            long int e = IGRAPH_EIT_GET(eit);+            VECTOR(*edges)[ptr++] = IGRAPH_FROM(graph, e);+            VECTOR(*edges)[ptr++] = IGRAPH_TO(graph, e);+        }+    } else {+        for (; !IGRAPH_EIT_END(eit); IGRAPH_EIT_NEXT(eit)) {+            long int e = IGRAPH_EIT_GET(eit);+            VECTOR(*edges)[ptr++] = IGRAPH_TO(graph, e);+            VECTOR(*edges)[ptr++] = IGRAPH_FROM(graph, e);+        }+    }++    igraph_eit_destroy(&eit);+    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;+}
+ igraph/src/types.c view
@@ -0,0 +1,146 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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);+    }+}+
+ igraph/src/typesize.c view
@@ -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
+ igraph/src/uintseqhash.cc view
@@ -0,0 +1,117 @@+#include "uintseqhash.hh"++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++/*+ * Random bits generated by+ * http://www.fourmilab.ch/hotbits/+ */+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 UintSeqHash::update(unsigned int i)+{+  i++;+  while(i > 0)+    {+      h ^= rtab[i & 0xff];+#if 1+      const unsigned int b = (h & 0x80000000) >> 31;+      i = i >> 8;+      h = (h << 1) | b;+#else+      const unsigned int b = h & 0x80000000;+      h = h << 1;+      if(b != 0)+	h++;+      i = i >> 8;+#endif+    }+}+++} // namespace bliss
+ igraph/src/uio.c view
@@ -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
+ igraph/src/uninit.c view
@@ -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+ */+++#ifdef __GLIBC__+#define IEEE0_done++#if ((__GLIBC__>=2) && (__GLIBC_MINOR__>=2))+#define _GNU_SOURCE 1+#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();+}++/* 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 */++#else /* __GLIBC__<2.2 */+#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@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@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 /* __GLIBC__>2.2 */+#endif /* __GLIBC__ */++/* 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
+ igraph/src/util.c view
@@ -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
+ igraph/src/utils.cc view
@@ -0,0 +1,122 @@+#include <cassert>+#include <vector>+#include "utils.hh"++/*+  Copyright (c) 2003-2015 Tommi Junttila+  Released under the GNU Lesser General Public License version 3.+  +  This file is part of bliss.+  +  bliss 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, version 3 of the License.++  bliss is distributed in the hope that 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 bliss.  If not, see <http://www.gnu.org/licenses/>.+*/++namespace bliss {++void+print_permutation(FILE* const fp,+		  const unsigned int N,+		  const unsigned int* perm,+		  const unsigned int offset)+{+  assert(N > 0);+  assert(perm);+  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+offset);+    j = perm[i];+    while(j != i) {+      fprintf(fp, "%u", j+offset);+      j = perm[j];+      if(j != i)+        fprintf(fp, ",");+    }+    fprintf(fp, ")");+  }+}++void+print_permutation(FILE* const fp,+		  const std::vector<unsigned int>& perm,+		  const unsigned int offset)+{+  const unsigned int N = perm.size();+  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+offset);+    j = perm[i];+    while(j != i) {+      fprintf(fp, "%u", j+offset);+      j = perm[j];+      if(j != i)+        fprintf(fp, ",");+    }+    fprintf(fp, ")");+  }+}++bool+is_permutation(const unsigned int N, const unsigned int* perm)+{+  if(N == 0)+    return true;+  std::vector<bool> m(N, false);+  for(unsigned int i = 0; i < N; i++) {+    if(perm[i] >= N) return false;+    if(m[perm[i]]) return false;+    m[perm[i]] = true;+  }+  return true;+}++bool+is_permutation(const std::vector<unsigned int>& perm)+{+  const unsigned int N = perm.size();+  if(N == 0)+    return true;+  std::vector<bool> m(N, false);+  for(unsigned int i = 0; i < N; i++) {+    if(perm[i] >= N) return false;+    if(m[perm[i]]) return false;+    m[perm[i]] = true;+  }+  return true;+}+++} // namespace bliss
+ igraph/src/vector.c view
@@ -0,0 +1,466 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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 "bigint.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_FLOAT+#include "igraph_pmt.h"+#include "vector.pmt"+#include "igraph_pmt_off.h"+#undef BASE_FLOAT++#define BASE_LONG+#include "igraph_pmt.h"+#include "vector.pmt"+#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++#define BASE_LIMB+#include "igraph_pmt.h"+#include "vector.pmt"+#include "igraph_pmt_off.h"+#undef BASE_LIMB++#include "igraph_math.h"++int igraph_vector_floor(const igraph_vector_t *from, igraph_vector_long_t *to) {+    long int i, n = igraph_vector_size(from);++    IGRAPH_CHECK(igraph_vector_long_resize(to, n));+    for (i = 0; i < n; i++) {+        VECTOR(*to)[i] = (long int) floor(VECTOR(*from)[i]);+    }+    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;+    }+}++int igraph_vector_zapsmall(igraph_vector_t *v, igraph_real_t tol) {+    int i, n = igraph_vector_size(v);+    if (tol < 0.0) {+        IGRAPH_ERROR("`tol' tolerance must be non-negative", IGRAPH_EINVAL);+    }+    if (tol == 0.0) {+        tol = sqrt(DBL_EPSILON);+    }+    for (i = 0; i < n; i++) {+        igraph_real_t val = VECTOR(*v)[i];+        if (val < tol && val > -tol) {+            VECTOR(*v)[i] = 0.0;+        }+    }+    return 0;+}
+ igraph/src/vector_ptr.c view
@@ -0,0 +1,628 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2003-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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) {+    assert(v != NULL);+    assert(v->stor_begin != NULL);+    assert(v->stor_begin != v->end);+    v->end -= 1;+    return *(v->end);+}++/**+ * \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;+}
+ igraph/src/version.c view
@@ -0,0 +1,67 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2008-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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;+}
+ igraph/src/visitors.c view
@@ -0,0 +1,593 @@+/* -*- mode: C -*-  */+/*+   IGraph R package.+   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public License+   along 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; ) {++        /* 'root' first, then all other vertices */+        if (igraph_stack_empty(&stack)) {+            if (!unreachable) {+                break;+            }+            if (VECTOR(added)[actroot]) {+                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;+                }+            }+            actroot++;+        }++        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;+}
+ igraph/src/walktrap.cpp view
@@ -0,0 +1,174 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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;+}
+ igraph/src/walktrap_communities.cpp view
@@ -0,0 +1,937 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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 */
+ igraph/src/walktrap_graph.cpp view
@@ -0,0 +1,254 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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;+}++}+}++++++++++
+ igraph/src/walktrap_heap.cpp view
@@ -0,0 +1,245 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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@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);+}
+ igraph/src/wref.c view
@@ -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
+ igraph/src/wrtfmt.c view
@@ -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
+ igraph/src/wsfe.c view
@@ -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
+ igraph/src/wsle.c view
@@ -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
+ igraph/src/wsne.c view
@@ -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
+ igraph/src/xerbla.c view
@@ -0,0 +1,129 @@+/*  -- 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;++/* > \brief \b XERBLA   ++    =========== DOCUMENTATION ===========   ++   Online html documentation available at   +              http://www.netlib.org/lapack/explore-html/   ++   > \htmlonly   +   > Download XERBLA + dependencies   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.tgz?format=tgz&filename=/lapack/lapack_routine/xerbla.+f">   +   > [TGZ]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.zip?format=zip&filename=/lapack/lapack_routine/xerbla.+f">   +   > [ZIP]</a>   +   > <a href="http://www.netlib.org/cgi-bin/netlibfiles.txt?format=txt&filename=/lapack/lapack_routine/xerbla.+f">   +   > [TXT]</a>   +   > \endhtmlonly   ++    Definition:   +    ===========   ++         SUBROUTINE XERBLA( SRNAME, INFO )   ++         CHARACTER*(*)      SRNAME   +         INTEGER            INFO   +++   > \par Purpose:   +    =============   +   >   +   > \verbatim   +   >   +   > 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.   +   > \endverbatim   ++    Arguments:   +    ==========   ++   > \param[in] SRNAME   +   > \verbatim   +   >          SRNAME is CHARACTER*(*)   +   >          The name of the routine which called XERBLA.   +   > \endverbatim   +   >   +   > \param[in] INFO   +   > \verbatim   +   >          INFO is INTEGER   +   >          The position of the invalid parameter in the parameter list   +   >          of the calling routine.   +   > \endverbatim   ++    Authors:   +    ========   ++   > \author Univ. of Tennessee   +   > \author Univ. of California Berkeley   +   > \author Univ. of Colorado Denver   +   > \author NAG Ltd.   ++   > \date November 2011   ++   > \ingroup auxOTHERauxiliary   ++    =====================================================================   +   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.4.0) --   +    -- LAPACK is a software package provided by Univ. of Tennessee,    --   +    -- Univ. of California Berkeley, Univ. of Colorado Denver and NAG Ltd..--   +       November 2011   +++   ===================================================================== */+++    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_ */+
+ igraph/src/xwsne.c view
@@ -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
+ igraph/src/z_abs.c view
@@ -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
+ igraph/src/z_cos.c view
@@ -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
+ igraph/src/z_div.c view
@@ -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
+ igraph/src/z_exp.c view
@@ -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
+ igraph/src/z_log.c view
@@ -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
+ igraph/src/z_sin.c view
@@ -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
+ igraph/src/z_sqrt.c view
@@ -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
+ igraph/src/zeroin.c view
@@ -0,0 +1,203 @@+/* -*- mode: C -*-  */+/*+   IGraph library.+   Copyright (C) 2007-2012  Gabor Csardi <csardi.gabor@gmail.com>+   334 Harvard street, Cambridge, MA 02139 USA++   This program is free software; you can redistribute it and/or modify+   it under the terms of the GNU General Public License as published by+   the Free Software Foundation; either version 2 of the License, or+   (at your option) any later version.++   This program is distributed in the hope that it will be useful,+   but WITHOUT ANY WARRANTY; without even the implied warranty of+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+   GNU General Public License for more details.++   You should have received a copy of the GNU General Public 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;+}+
+ igraph/src/zeta.c view
@@ -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;+}+
include/bytestring.h view
@@ -1,7 +1,7 @@ #ifndef HASKELL_IGRAPH_BYTESTRING #define HASKELL_IGRAPH_BYTESTRING -#include <igraph/igraph.h>+#include "igraph.h"  typedef struct bytestring_t {   unsigned long int len;
include/haskell_attributes.h view
@@ -1,7 +1,7 @@ #ifndef HASKELL_IGRAPH_ATTRIBUTE #define HASKELL_IGRAPH_ATTRIBUTE -#include "igraph/igraph.h"+#include "igraph.h" #include "bytestring.h"  #include <string.h>
include/haskell_igraph.h view
@@ -1,7 +1,7 @@ #ifndef HASKELL_IGRAPH #define HASKELL_IGRAPH -#include <igraph/igraph.h>+#include "igraph.h"  void haskelligraph_init(); 
src/IGraph/Algorithms.hs view
@@ -2,7 +2,7 @@     ( module IGraph.Algorithms.Structure     , module IGraph.Algorithms.Community     , module IGraph.Algorithms.Clique-    , module IGraph.Algorithms.Layout+--    , module IGraph.Algorithms.Layout     , module IGraph.Algorithms.Motif     , module IGraph.Algorithms.Generators     , module IGraph.Algorithms.Isomorphism@@ -12,7 +12,7 @@ import IGraph.Algorithms.Structure import IGraph.Algorithms.Community import IGraph.Algorithms.Clique-import IGraph.Algorithms.Layout+--import IGraph.Algorithms.Layout import IGraph.Algorithms.Motif import IGraph.Algorithms.Generators import IGraph.Algorithms.Isomorphism
src/IGraph/Algorithms/Generators.chs view
@@ -22,6 +22,7 @@ import Foreign  import           IGraph+import           IGraph.Random (Gen) import           IGraph.Mutable (MGraph(..)) {#import IGraph.Internal #} {#import IGraph.Internal.Constants #}@@ -86,8 +87,9 @@ erdosRenyiGame :: forall d. SingI d                => ErdosRenyiModel                -> Bool  -- ^ self-loop+               -> Gen                -> IO (Graph d () ())-erdosRenyiGame model self = do+erdosRenyiGame model self _ = do     igraphInit     gr <- case model of         GNP n p -> igraphErdosRenyiGame IgraphErdosRenyiGnp n p directed self@@ -107,8 +109,9 @@ -- | Generates a random graph with a given degree sequence. degreeSequenceGame :: [Int]   -- ^ Out degree                    -> [Int]   -- ^ In degree+                   -> Gen                    -> IO (Graph 'D () ())-degreeSequenceGame out_deg in_deg = do+degreeSequenceGame out_deg in_deg _ = do     igraphInit     withList out_deg $ \out_deg' ->         withList in_deg $ \in_deg' -> do@@ -127,8 +130,9 @@                         -- one (inclusive).             -> Bool     -- ^ whether loop edges are allowed in the new graph, or not.             -> Bool     -- ^ whether multiple edges are allowed in the new graph.+            -> Gen             -> IO ()-rewireEdges gr p loop multi = igraphRewireEdges (_mgraph gr) p loop multi+rewireEdges gr p loop multi _ = igraphRewireEdges (_mgraph gr) p loop multi {#fun igraph_rewire_edges as ^      { `IGraph'     , `Double'@@ -140,8 +144,9 @@ rewire :: (Serialize v, Ord v, Serialize e)        => Int    -- ^ Number of rewiring trials to perform.        -> Graph d v e+       -> Gen        -> IO (Graph d v e)-rewire n gr = do+rewire n gr _ = do     gr' <- thaw gr     igraphRewire (_mgraph gr') n IgraphRewiringSimple     unsafeFreeze gr'
− src/IGraph/Algorithms/Layout.chs
@@ -1,113 +0,0 @@-{-# LANGUAGE ForeignFunctionInterface #-}-module IGraph.Algorithms.Layout-    ( getLayout-    , LayoutMethod(..)-    , defaultKamadaKawai-    , defaultLGL-    ) where--import           Data.Maybe             (isJust)-import           Foreign                (nullPtr)--import Foreign--import           IGraph-{#import IGraph.Internal #}--#include "igraph/igraph.h"--data LayoutMethod =-    KamadaKawai { kk_seed      :: !(Maybe [(Double, Double)])-                , kk_nIter     :: !Int-                , kk_sigma     :: (Int -> Double) -- ^ The base standard deviation of-                -- position change proposals-                , kk_startTemp :: !Double  -- ^ The initial temperature for the annealing-                , kk_coolFact  :: !Double  -- ^ The cooling factor for the simulated annealing-                , kk_const     :: (Int -> Double)  -- ^ The Kamada-Kawai vertex attraction constant-                }-  | LGL { lgl_nIter      :: !Int-        , lgl_maxdelta   :: (Int -> Double)  -- ^ The maximum length of the move allowed-        -- for a vertex in a single iteration. A reasonable default is the number of vertices.-        , lgl_area       :: (Int -> Double)  -- ^ This parameter gives the area-        -- of the square on which the vertices will be placed. A reasonable-        -- default value is the number of vertices squared.-        , lgl_coolexp    :: !Double  -- ^ The cooling exponent. A reasonable default value is 1.5.-        , lgl_repulserad :: (Int -> Double) -- ^ Determines the radius at which-        -- vertex-vertex repulsion cancels out attraction of adjacent vertices.-        -- A reasonable default value is area times the number of vertices.-        , lgl_cellsize   :: (Int -> Double)-        }--defaultKamadaKawai :: LayoutMethod-defaultKamadaKawai = KamadaKawai-    { kk_seed = Nothing-    , kk_nIter = 10-    , kk_sigma = \x -> fromIntegral x / 4-    , kk_startTemp = 10-    , kk_coolFact = 0.99-    , kk_const = \x -> fromIntegral $ x^2-    }--defaultLGL :: LayoutMethod-defaultLGL = LGL-    { lgl_nIter = 100-    , lgl_maxdelta = \x -> fromIntegral x-    , lgl_area = area-    , lgl_coolexp = 1.5-    , lgl_repulserad = \x -> fromIntegral x * area x-    , lgl_cellsize = \x -> area x ** 0.25-    }-  where-    area x = fromIntegral $ x^2--getLayout :: Graph d v e -> LayoutMethod -> IO [(Double, Double)]-getLayout gr method = case method of-    KamadaKawai seed niter sigma initemp coolexp kkconst -> case seed of-        Nothing -> allocaMatrix $ \mat -> do-            igraphLayoutKamadaKawai gptr mat niter (sigma n) initemp coolexp-                (kkconst n) (isJust seed) nullPtr nullPtr nullPtr nullPtr-            [x, y] <- toColumnLists mat-            return $ zip x y-        Just xs -> if length xs /= nNodes gr-            then error "Seed error: incorrect size"-            else withRowLists ((\(x,y) -> [x,y]) (unzip xs)) $ \mat -> do-                igraphLayoutKamadaKawai gptr mat niter (sigma n) initemp coolexp-                    (kkconst n) (isJust seed) nullPtr nullPtr nullPtr nullPtr-                [x, y] <- toColumnLists mat-                return $ zip x y--    LGL niter delta area coolexp repulserad cellsize -> allocaMatrix $ \mat -> do-        igraphLayoutLgl gptr mat niter (delta n) (area n) coolexp-            (repulserad n) (cellsize n) (-1)-        [x, y] <- toColumnLists mat-        return $ zip x y-  where-    n = nNodes gr-    gptr = _graph gr--{#fun igraph_layout_kamada_kawai as ^-    { `IGraph'-    , castPtr `Ptr Matrix'-    , `Int'-    , `Double'-    , `Double'-    , `Double'-    , `Double'-    , `Bool'-    , castPtr `Ptr Vector'-    , castPtr `Ptr Vector'-    , castPtr `Ptr Vector'-    , castPtr `Ptr Vector'-    } -> `CInt' void- #}--{# fun igraph_layout_lgl as ^-    { `IGraph'-    , castPtr `Ptr Matrix'-    , `Int'-    , `Double'-    , `Double'-    , `Double'-    , `Double'-    , `Double'-    , `Int'-    } -> `CInt' void- #}
− src/IGraph/Exporter/GEXF.hs
@@ -1,129 +0,0 @@-{-# LANGUAGE DeriveGeneric     #-}-{-# LANGUAGE FlexibleInstances #-}-module IGraph.Exporter.GEXF-    ( NodeAttr(..)-    , defaultNodeAttributes-    , EdgeAttr(..)-    , defaultEdgeAttributes-    , genXMLTree-    , writeGEXF-    ) where--import           Data.Colour       (AlphaColour, alphaChannel, black, opaque,-                                    over)-import           Data.Colour.SRGB  (channelBlue, channelGreen, channelRed,-                                    toSRGB24)-import           Data.Serialize-import Data.Function (on)-import           Data.Singletons   (SingI)-import           GHC.Generics-import           IGraph-import           Text.XML.HXT.Core--instance Serialize (AlphaColour Double) where-    get = do-        x <- get-        return $ read x-    put x = put $ show x--data NodeAttr = NodeAttr-    { _size       :: Double-    , _nodeColour :: AlphaColour Double-    , _nodeLabel  :: String-    , _positionX  :: Double-    , _positionY  :: Double-    , _nodeZindex :: Int-    } deriving (Show, Read, Eq, Generic)--instance Ord NodeAttr where-    compare = compare `on` _nodeLabel-instance Serialize NodeAttr--defaultNodeAttributes :: NodeAttr-defaultNodeAttributes = NodeAttr-    { _size = 0.15-    , _nodeColour = opaque black-    , _nodeLabel = ""-    , _positionX = 0-    , _positionY = 0-    , _nodeZindex = 1-    }--data EdgeAttr = EdgeAttr-    { _edgeLabel       :: String-    , _edgeColour      :: AlphaColour Double-    , _edgeWeight      :: Double-    , _edgeArrowLength :: Double-    , _edgeZindex      :: Int-    } deriving (Show, Read, Eq, Generic)--instance Ord EdgeAttr where-    compare = compare `on` _edgeLabel-instance Serialize EdgeAttr--defaultEdgeAttributes :: EdgeAttr-defaultEdgeAttributes = EdgeAttr-    { _edgeLabel = ""-    , _edgeColour = opaque black-    , _edgeWeight = 1.0-    , _edgeArrowLength = 10-    , _edgeZindex = 2-    }--genXMLTree :: (SingI d, ArrowXml a) => Graph d NodeAttr EdgeAttr -> a XmlTree XmlTree-genXMLTree gr = root [] [gexf]-  where-    gexf = mkelem "gexf" [ attr "version" $ txt "1.2"-                              , attr "xmlns" $ txt "http://www.gexf.net/1.2draft"-                              , attr "xmlns:viz" $ txt "http://www.gexf.net/1.2draft/viz"-                              , attr "xmlns:xsi" $ txt "http://www.w3.org/2001/XMLSchema-instance"-                              , attr "xsi:schemaLocation" $ txt "http://www.gexf.net/1.2draft http://www.gexf.net/1.2draft/gexf.xsd"-                              ] [graph]-    directed | isDirected gr = "directed"-             | otherwise = "undirected"-    graph = mkelem "graph" [ attr "mode" $ txt "static"-                           , attr "defaultedgetype" $ txt directed-                           ] [ns, es]-    ns = mkelem "nodes" [] $ map mkNode $ nodes gr-    es = mkelem "edges" [] $ map mkEdge $ edges gr-    mkNode i =-        mkelem "node" [ attr "id" $ txt $ show i-                      , attr "label" $ txt $ _nodeLabel at ]-                      [ aelem "viz:position" [ attr "x" $ txt $ show $ _positionX at-                                             , attr "y" $ txt $ show $ _positionY at ]-                      , aelem "viz:color" [ attr "r" $ txt r-                                          , attr "g" $ txt g-                                          , attr "b" $ txt b-                                          , attr "a" $ txt a ]-                      , aelem "viz:size" [attr "value" $ txt $ show $ _size at]-                      ]-      where-        at = nodeLab gr i-        rgb = toSRGB24 $ _nodeColour at `over` black-        r = show (fromIntegral $ channelRed rgb :: Int)-        b = show (fromIntegral $ channelBlue rgb :: Int)-        g = show (fromIntegral $ channelGreen rgb :: Int)-        a = show $ alphaChannel $ _nodeColour at--    mkEdge (fr,to) =-        mkelem "edge" [ attr "source" $ txt $ show fr-                      , attr "target" $ txt $ show to-                      , attr "weight" $ txt $ show $ _edgeWeight at ]-                      [ aelem "viz:color" [ attr "r" $ txt r-                                          , attr "g" $ txt g-                                          , attr "b" $ txt b-                                          , attr "a" $ txt a ]-                      ]-      where-        at = edgeLab gr (fr,to)-        rgb = toSRGB24 $ _edgeColour at `over` black-        r = show (fromIntegral $ channelRed rgb :: Int)-        b = show (fromIntegral $ channelBlue rgb :: Int)-        g = show (fromIntegral $ channelGreen rgb :: Int)-        a = show $ alphaChannel $ _edgeColour at-{-# INLINE genXMLTree #-}--writeGEXF :: SingI d => FilePath -> Graph d NodeAttr EdgeAttr -> IO ()-writeGEXF fl gr = runX (genXMLTree gr >>> writeDocument config fl) >> return ()-  where-    config = [withIndent yes]
− src/IGraph/Exporter/Graphics.hs
@@ -1,49 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs            #-}-module IGraph.Exporter.Graphics-    ( renderGraph-    , graphToDiagram-    ) where--import           Data.List              (sortBy)-import           Data.Ord               (comparing)-import           Diagrams.Backend.Cairo-import           Diagrams.Prelude-import           Diagrams.Size          (dims)--import           IGraph-import           IGraph.Exporter.GEXF--renderGraph :: Graph d => FilePath -> Double -> Double -> LGraph d NodeAttr EdgeAttr -> IO ()-renderGraph out w h gr = renderCairo out (dims $ w ^& h) $ graphToDiagram gr--graphToDiagram :: Graph d => LGraph d NodeAttr EdgeAttr -> Diagram B-graphToDiagram gr = mconcat $ fst $ unzip $ sortBy (flip (comparing snd)) $-    map drawNode (nodes gr) ++ map drawEdge (edges gr)-  where-    drawNode x = ( moveTo (_positionX nattr ^& _positionY nattr)-                          (circle (_size nattr) # lwO 0 # fcA (_nodeColour nattr))-                 , _nodeZindex nattr )-      where-        nattr = nodeLab gr x-    drawEdge (from, to) = ( arrowBetween'-        ( with & arrowTail .~ noTail-               & arrowHead .~ arrowH-               & headStyle %~ fcA (_edgeColour eattr)-               & headLength .~ output (_edgeArrowLength eattr)-        ) start end # lwO (_edgeWeight eattr) # lcA (_edgeColour eattr), _edgeZindex eattr )-      where-        eattr = edgeLab gr (from, to)-        start = x1 ^& y1-        end = (alpha * x1 + (1 - alpha) * x2) ^& (alpha * y1 + (1 - alpha) * y2)-        x1 = _positionX nattr1-        y1 = _positionY nattr1-        x2 = _positionX nattr2-        y2 = _positionY nattr2-        alpha = r / sqrt ((x1 - x2)**2 + (y1 - y2)**2)-        r = _size nattr2-        nattr1 = nodeLab gr from-        nattr2 = nodeLab gr to-        arrowH | isDirected gr = dart-               | otherwise = noHead-{-# INLINE graphToDiagram #-}
src/IGraph/Internal.chs view
@@ -115,6 +115,13 @@       -- * Igraph arpack options type     , ArpackOpt     , allocaArpackOpt++      -- * Random numbers+    , RNG+    , igraphRngDefault+    , igraphRngSetDefault+    , allocaRng+    , igraphRngSeed     ) where  import Control.Monad@@ -125,7 +132,6 @@ import qualified Data.Map.Strict as M import           System.IO.Unsafe          (unsafePerformIO) import Data.Either (fromRight)-import Data.List.Split (chunksOf) import Data.Serialize (Serialize, decode, encode) import           Control.Monad.Primitive import Control.Exception (bracket_)@@ -341,6 +347,9 @@         igraphMatrixCopyTo mptr ptr         peekArray (r*c) ptr     return $ chunksOf r $ map realToFrac xs+  where+    chunksOf _ [] = []+    chunksOf i ls = take i ls : chunksOf i (drop i ls)  {#fun igraph_matrix_null as ^ { castPtr `Ptr Matrix' } -> `()' #} @@ -749,3 +758,36 @@     igraphArpackOptionsInit opt >> fun opt {-# INLINE allocaArpackOpt #-} {#fun igraph_arpack_options_init as ^ { castPtr `Ptr ArpackOpt' } -> `CInt' void- #}+++--------------------------------------------------------------------------------+-- Random numbers+--------------------------------------------------------------------------------++data RNG++-- | Query the default random number generator.+{#fun igraph_rng_default as ^ {} -> `Ptr RNG' castPtr #}++-- | Set the default igraph random number generator.+{#fun igraph_rng_set_default as ^ { castPtr `Ptr RNG' } -> `()' #}++-- | Allocate and initialize a RNG.+allocaRng :: (Ptr RNG -> IO a) -> IO a+allocaRng fun = allocaBytes {# sizeof igraph_rng_t #} $ \rng ->+    bracket_ (igraphRngInit_ rng) (igraphRngDestroy rng) (fun rng)+{-# INLINE allocaRng #-}++{#fun igraph_rng_init_ as igraphRngInit_+    { castPtr `Ptr RNG' } -> `CInt' void- #}+{#fun igraph_rng_destroy as ^ { castPtr `Ptr RNG' } -> `()' #}++-- | Set the seed of a random number generator+{#fun igraph_rng_seed as ^+    { castPtr `Ptr RNG', `Int' } -> `CInt' void- #}++#c+int igraph_rng_init_(igraph_rng_t *rng) {+    return(igraph_rng_init(rng, &igraph_rngtype_mt19937));+}+#endc
src/IGraph/Internal/Constants.chs view
@@ -1,7 +1,7 @@ {-# LANGUAGE ForeignFunctionInterface #-} module IGraph.Internal.Constants where -#include "igraph/igraph.h"+#include "haskell_igraph.h"  {#enum igraph_neimode_t as Neimode {underscoreToCase}     deriving (Show, Eq) #}
+ src/IGraph/Random.hs view
@@ -0,0 +1,22 @@+module IGraph.Random+    ( Gen+    , withSeed+    ) where++import IGraph.Internal++-- | Random number generator+data Gen = Gen++{-+withSystemRandom :: (Gen -> IO a) -> IO a+withSystemRandom fun = fun Gen+{-# INLINE withSystemRandom #-}+-}++withSeed :: Int -> (Gen -> IO a) -> IO a+withSeed seed fun = do+    rng <- igraphRngDefault+    igraphRngSeed rng seed+    fun Gen+{-# INLINE withSeed #-}
+ stack.yaml view
@@ -0,0 +1,4 @@+packages:+    - '.'++resolver: lts-15.0
tests/Test/Algorithms.hs view
@@ -11,6 +11,7 @@ import           Test.Tasty.HUnit  import           IGraph+import           IGraph.Random import           IGraph.Algorithms import qualified IGraph.Mutable      as GM @@ -72,7 +73,7 @@     [ testCase "ring" $ edges (head $ decompose $ ring 10) @?=         [(0,1), (1,2), (2,3), (3,4), (4,5), (5,6), (6,7), (7,8), (8,9), (0,9)]     , testCase "1 component" $ do-        gr <- erdosRenyiGame (GNP 100 (40/100)) False :: IO (Graph 'U () ())+        gr <- (withSeed 1244 $ erdosRenyiGame (GNP 100 (40/100)) False) :: IO (Graph 'U () ())         1 @?= length (decompose gr)     , testCase "toy example" $ map (sort . edges) (decompose gr) @?=         [ [(0,1), (0,2), (1,2)]
tests/Test/Attributes.hs view
@@ -11,7 +11,6 @@ import           Test.Utils  import           IGraph-import           IGraph.Exporter.GEXF import           IGraph.Internal import           IGraph.Mutable @@ -19,7 +18,6 @@ tests = testGroup "Attribute tests"     [ nodeLabelTest     , labelTest-    , serializeTest     ]  nodeLabelTest :: TestTree@@ -36,6 +34,7 @@         es' = sort $ map (\(a,b) -> ((nodeLab gr a, nodeLab gr b), edgeLab gr (a,b))) $ edges gr     assertBool "" $ es == es' +{- serializeTest :: TestTree serializeTest = testCase "serialize test" $ do     dat <- randEdges 1000 10000@@ -49,3 +48,4 @@             Right r  -> r         es' = map (\(a,b) -> ((nodeLab gr' a, nodeLab gr' b), edgeLab gr' (a,b))) $ edges gr'     sort (map show es) @=? sort (map show es')+    -}
tests/Test/Basic.hs view
@@ -13,7 +13,9 @@ import           Test.Utils  import           IGraph+import           IGraph.Random import qualified IGraph.Mutable    as GM+import IGraph.Algorithms.Generators  tests :: TestTree tests = testGroup "Basic tests"@@ -21,6 +23,7 @@     , graphCreationLabeled     , graphEdit     , nonSimpleGraphTest+    , randomGeneratorTest     ]  graphCreation :: TestTree@@ -82,3 +85,18 @@          , ((0,2), 'd') ]     gr :: Graph 'U Int Char     gr = mkGraph [0,1,2] es++randomGeneratorTest :: TestTree+randomGeneratorTest = testGroup "random generator"+    [t1, t2]+  where+    t1 = testCase "random graph" $ do+        gr1 <- sort . edges <$> genGr 1244+        gr2 <- sort . edges <$> genGr 1244+        gr1 @=? gr2+    t2 = testCase "random graph" $ do+        gr1 <- sort . edges <$> genGr 145+        gr2 <- sort . edges <$> genGr 24+        assertBool "" $ gr1 /= gr2+    genGr :: Int -> IO (Graph 'D () ())+    genGr seed = withSeed seed $ erdosRenyiGame (GNP 500 0.5) False