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 +9/−1
- LICENSE +1/−1
- README.md +2/−0
- cbits/haskell_igraph.c +0/−1
- haskell-igraph.cabal +574/−25
- igraph/AUTHORS +4/−0
- igraph/COPYING +340/−0
- igraph/include/DensityGrid.h +88/−0
- igraph/include/DensityGrid_3d.h +88/−0
- igraph/include/NetDataTypes.h +926/−0
- igraph/include/NetRoutines.h +61/−0
- igraph/include/arith.h +9/−0
- igraph/include/array.pmt +90/−0
- igraph/include/atlas-edges.h +1296/−0
- igraph/include/bigint.h +107/−0
- igraph/include/bignum.h +125/−0
- igraph/include/bliss/bignum.hh +133/−0
- igraph/include/bliss/defs.hh +128/−0
- igraph/include/bliss/graph.hh +997/−0
- igraph/include/bliss/heap.hh +83/−0
- igraph/include/bliss/kqueue.hh +162/−0
- igraph/include/bliss/kstack.hh +141/−0
- igraph/include/bliss/orbit.hh +111/−0
- igraph/include/bliss/partition.hh +308/−0
- igraph/include/bliss/uintseqhash.hh +65/−0
- igraph/include/bliss/utils.hh +69/−0
- igraph/include/cliquer/cliquer.h +57/−0
- igraph/include/cliquer/cliquerconf.h +68/−0
- igraph/include/cliquer/graph.h +75/−0
- igraph/include/cliquer/misc.h +73/−0
- igraph/include/cliquer/reorder.h +26/−0
- igraph/include/cliquer/set.h +389/−0
- igraph/include/config.h +39/−0
- igraph/include/cs/UFconfig.h +118/−0
- igraph/include/cs/cs.h +756/−0
- igraph/include/dqueue.pmt +384/−0
- igraph/include/drl_Node.h +68/−0
- igraph/include/drl_Node_3d.h +68/−0
- igraph/include/drl_graph.h +128/−0
- igraph/include/drl_graph_3d.h +120/−0
- igraph/include/drl_layout.h +65/−0
- igraph/include/drl_layout_3d.h +65/−0
- igraph/include/drl_parse.h +70/−0
- igraph/include/f2c.h +234/−0
- igraph/include/f2c/fio.h +141/−0
- igraph/include/f2c/fmt.h +105/−0
- igraph/include/f2c/fp.h +28/−0
- igraph/include/f2c/lio.h +74/−0
- igraph/include/f2c/signal1.h +35/−0
- igraph/include/f2c/sysdep1.h +76/−0
- igraph/include/foreign-dl-header.h +42/−0
- igraph/include/foreign-dl-parser.h +107/−0
- igraph/include/foreign-gml-header.h +30/−0
- igraph/include/foreign-gml-parser.h +97/−0
- igraph/include/foreign-lgl-header.h +35/−0
- igraph/include/foreign-lgl-parser.h +87/−0
- igraph/include/foreign-ncol-header.h +34/−0
- igraph/include/foreign-ncol-parser.h +85/−0
- igraph/include/foreign-pajek-header.h +43/−0
- igraph/include/foreign-pajek-parser.h +181/−0
- igraph/include/gengraph_box_list.h +89/−0
- igraph/include/gengraph_definitions.h +216/−0
- igraph/include/gengraph_degree_sequence.h +101/−0
- igraph/include/gengraph_graph_molloy_hash.h +219/−0
- igraph/include/gengraph_graph_molloy_optimized.h +288/−0
- igraph/include/gengraph_hash.h +308/−0
- igraph/include/gengraph_header.h +120/−0
- igraph/include/gengraph_powerlaw.h +86/−0
- igraph/include/gengraph_qsort.h +568/−0
- igraph/include/gengraph_random.h +216/−0
- igraph/include/gengraph_vertex_cover.h +75/−0
- igraph/include/heap.pmt +350/−0
- igraph/include/hrg_dendro.h +316/−0
- igraph/include/hrg_graph.h +169/−0
- igraph/include/hrg_graph_simp.h +163/−0
- igraph/include/hrg_rbtree.h +164/−0
- igraph/include/hrg_splittree_eq.h +185/−0
- igraph/include/igraph.h +100/−0
- igraph/include/igraph_adjlist.h +232/−0
- igraph/include/igraph_arpack.h +333/−0
- igraph/include/igraph_arpack_internal.h +219/−0
- igraph/include/igraph_array.h +61/−0
- igraph/include/igraph_array_pmt.h +51/−0
- igraph/include/igraph_attributes.h +873/−0
- igraph/include/igraph_bipartite.h +97/−0
- igraph/include/igraph_blas.h +65/−0
- igraph/include/igraph_blas_internal.h +65/−0
- igraph/include/igraph_centrality.h +212/−0
- igraph/include/igraph_cliquer.h +29/−0
- igraph/include/igraph_cliques.h +114/−0
- igraph/include/igraph_cocitation.h +66/−0
- igraph/include/igraph_cohesive_blocks.h +41/−0
- igraph/include/igraph_coloring.h +23/−0
- igraph/include/igraph_community.h +247/−0
- igraph/include/igraph_complex.h +104/−0
- igraph/include/igraph_components.h +61/−0
- igraph/include/igraph_constants.h +193/−0
- igraph/include/igraph_constructors.h +80/−0
- igraph/include/igraph_conversion.h +66/−0
- igraph/include/igraph_datatype.h +83/−0
- igraph/include/igraph_decls.h +26/−0
- igraph/include/igraph_dqueue.h +73/−0
- igraph/include/igraph_dqueue_pmt.h +49/−0
- igraph/include/igraph_eigen.h +112/−0
- igraph/include/igraph_embedding.h +69/−0
- igraph/include/igraph_epidemics.h +66/−0
- igraph/include/igraph_error.h +720/−0
- igraph/include/igraph_estack.h +47/−0
- igraph/include/igraph_flow.h +169/−0
- igraph/include/igraph_flow_internal.h +42/−0
- igraph/include/igraph_foreign.h +85/−0
- igraph/include/igraph_games.h +227/−0
- igraph/include/igraph_glpk_support.h +48/−0
- igraph/include/igraph_gml_tree.h +91/−0
- igraph/include/igraph_graphlets.h +52/−0
- igraph/include/igraph_hacks_internal.h +57/−0
- igraph/include/igraph_heap.h +83/−0
- igraph/include/igraph_heap_pmt.h +45/−0
- igraph/include/igraph_hrg.h +114/−0
- igraph/include/igraph_interface.h +86/−0
- igraph/include/igraph_interrupt.h +128/−0
- igraph/include/igraph_interrupt_internal.h +69/−0
- igraph/include/igraph_iterators.h +401/−0
- igraph/include/igraph_lapack.h +114/−0
- igraph/include/igraph_lapack_internal.h +184/−0
- igraph/include/igraph_layout.h +250/−0
- igraph/include/igraph_lsap.h +16/−0
- igraph/include/igraph_marked_queue.h +70/−0
- igraph/include/igraph_matching.h +56/−0
- igraph/include/igraph_math.h +100/−0
- igraph/include/igraph_matrix.h +100/−0
- igraph/include/igraph_matrix_pmt.h +243/−0
- igraph/include/igraph_memory.h +47/−0
- igraph/include/igraph_microscopic_update.h +60/−0
- igraph/include/igraph_mixing.h +51/−0
- igraph/include/igraph_motifs.h +97/−0
- igraph/include/igraph_neighborhood.h +47/−0
- igraph/include/igraph_nongraph.h +93/−0
- igraph/include/igraph_operators.h +63/−0
- igraph/include/igraph_paths.h +146/−0
- igraph/include/igraph_pmt.h +150/−0
- igraph/include/igraph_pmt_off.h +158/−0
- igraph/include/igraph_progress.h +183/−0
- igraph/include/igraph_psumtree.h +58/−0
- igraph/include/igraph_qsort.h +40/−0
- igraph/include/igraph_random.h +133/−0
- igraph/include/igraph_scan.h +69/−0
- igraph/include/igraph_scg.h +142/−0
- igraph/include/igraph_separators.h +53/−0
- igraph/include/igraph_sparsemat.h +287/−0
- igraph/include/igraph_spmatrix.h +114/−0
- igraph/include/igraph_stack.h +79/−0
- igraph/include/igraph_stack_pmt.h +47/−0
- igraph/include/igraph_statusbar.h +126/−0
- igraph/include/igraph_structural.h +151/−0
- igraph/include/igraph_strvector.h +97/−0
- igraph/include/igraph_threading.h +43/−0
- igraph/include/igraph_topology.h +292/−0
- igraph/include/igraph_transitivity.h +64/−0
- igraph/include/igraph_types.h +91/−0
- igraph/include/igraph_types_internal.h +395/−0
- igraph/include/igraph_vector.h +184/−0
- igraph/include/igraph_vector_pmt.h +265/−0
- igraph/include/igraph_vector_ptr.h +100/−0
- igraph/include/igraph_vector_type.h +34/−0
- igraph/include/igraph_version.h +46/−0
- igraph/include/igraph_visitor.h +132/−0
- igraph/include/infomap_FlowGraph.h +78/−0
- igraph/include/infomap_Greedy.h +85/−0
- igraph/include/infomap_Node.h +55/−0
- igraph/include/matrix.pmt +1634/−0
- igraph/include/maximal_cliques_template.h +409/−0
- igraph/include/plfit/arithmetic_ansi.h +133/−0
- igraph/include/plfit/arithmetic_sse_double.h +294/−0
- igraph/include/plfit/arithmetic_sse_float.h +291/−0
- igraph/include/plfit/error.h +86/−0
- igraph/include/plfit/gss.h +146/−0
- igraph/include/plfit/kolmogorov.h +43/−0
- igraph/include/plfit/lbfgs.h +736/−0
- igraph/include/plfit/platform.h +54/−0
- igraph/include/plfit/plfit.h +109/−0
- igraph/include/plfit/zeta.h +53/−0
- igraph/include/pottsmodel_2.h +167/−0
- igraph/include/prpack.h +54/−0
- igraph/include/prpack/prpack.h +11/−0
- igraph/include/prpack/prpack_base_graph.h +42/−0
- igraph/include/prpack/prpack_csc.h +30/−0
- igraph/include/prpack/prpack_csr.h +16/−0
- igraph/include/prpack/prpack_edge_list.h +16/−0
- igraph/include/prpack/prpack_igraph_graph.h +26/−0
- igraph/include/prpack/prpack_preprocessed_ge_graph.h +26/−0
- igraph/include/prpack/prpack_preprocessed_graph.h +17/−0
- igraph/include/prpack/prpack_preprocessed_gs_graph.h +30/−0
- igraph/include/prpack/prpack_preprocessed_scc_graph.h +39/−0
- igraph/include/prpack/prpack_preprocessed_schur_graph.h +33/−0
- igraph/include/prpack/prpack_result.h +27/−0
- igraph/include/prpack/prpack_solver.h +178/−0
- igraph/include/prpack/prpack_utils.h +34/−0
- igraph/include/scg_headers.h +128/−0
- igraph/include/stack.pmt +294/−0
- igraph/include/structural_properties_internal.h +47/−0
- igraph/include/triangles_template.h +118/−0
- igraph/include/triangles_template1.h +88/−0
- igraph/include/vector.pmt +2684/−0
- igraph/include/walktrap_communities.h +176/−0
- igraph/include/walktrap_graph.h +108/−0
- igraph/include/walktrap_heap.h +134/−0
- igraph/src/DensityGrid.cpp +284/−0
- igraph/src/DensityGrid_3d.cpp +308/−0
- igraph/src/NetDataTypes.cpp +222/−0
- igraph/src/NetRoutines.cpp +286/−0
- igraph/src/abort_.c +22/−0
- igraph/src/adjlist.c +930/−0
- igraph/src/arithchk.c +262/−0
- igraph/src/arpack.c +1429/−0
- igraph/src/array.c +50/−0
- igraph/src/atlas.c +82/−0
- igraph/src/attributes.c +442/−0
- igraph/src/backspac.c +76/−0
- igraph/src/basic_query.c +64/−0
- igraph/src/bfgs.c +223/−0
- igraph/src/bigint.c +329/−0
- igraph/src/bignum.c +1984/−0
- igraph/src/bipartite.c +1147/−0
- igraph/src/blas.c +110/−0
- igraph/src/bliss.cc +262/−0
- igraph/src/bliss_heap.cc +99/−0
- igraph/src/c_abs.c +20/−0
- igraph/src/c_cos.c +23/−0
- igraph/src/c_div.c +53/−0
- igraph/src/c_exp.c +25/−0
- igraph/src/c_log.c +23/−0
- igraph/src/c_sin.c +23/−0
- igraph/src/c_sqrt.c +41/−0
- igraph/src/cabs.c +33/−0
- igraph/src/cattributes.c +4211/−0
- igraph/src/centrality.c +3516/−0
- igraph/src/cliquer.c +1778/−0
- igraph/src/cliquer_graph.c +768/−0
- igraph/src/cliques.c +1399/−0
- igraph/src/close.c +101/−0
- igraph/src/clustertool.cpp +693/−0
- igraph/src/cocitation.c +780/−0
- igraph/src/cohesive_blocks.c +612/−0
- igraph/src/coloring.c +142/−0
- igraph/src/community.c +3840/−0
- igraph/src/community_leiden.c +1079/−0
- igraph/src/complex.c +392/−0
- igraph/src/components.c +1248/−0
- igraph/src/conversion.c +953/−0
- igraph/src/cores.c +159/−0
- igraph/src/cs_add.c +48/−0
- igraph/src/cs_amd.c +384/−0
- igraph/src/cs_chol.c +79/−0
- igraph/src/cs_cholsol.c +46/−0
- igraph/src/cs_compress.c +42/−0
- igraph/src/cs_counts.c +81/−0
- igraph/src/cs_cumsum.c +37/−0
- igraph/src/cs_dfs.c +56/−0
- igraph/src/cs_dmperm.c +164/−0
- igraph/src/cs_droptol.c +29/−0
- igraph/src/cs_dropzeros.c +29/−0
- igraph/src/cs_dupl.c +54/−0
- igraph/src/cs_entry.c +33/−0
- igraph/src/cs_ereach.c +43/−0
- igraph/src/cs_etree.c +50/−0
- igraph/src/cs_fkeep.c +45/−0
- igraph/src/cs_gaxpy.c +37/−0
- igraph/src/cs_happly.c +39/−0
- igraph/src/cs_house.c +50/−0
- igraph/src/cs_ipvec.c +29/−0
- igraph/src/cs_leaf.c +42/−0
- igraph/src/cs_load.c +46/−0
- igraph/src/cs_lsolve.c +38/−0
- igraph/src/cs_ltsolve.c +38/−0
- igraph/src/cs_lu.c +107/−0
- igraph/src/cs_lusol.c +46/−0
- igraph/src/cs_malloc.c +55/−0
- igraph/src/cs_maxtrans.c +112/−0
- igraph/src/cs_multiply.c +55/−0
- igraph/src/cs_norm.c +36/−0
- igraph/src/cs_permute.c +45/−0
- igraph/src/cs_pinv.c +31/−0
- igraph/src/cs_post.c +44/−0
- igraph/src/cs_print.c +66/−0
- igraph/src/cs_pvec.c +29/−0
- igraph/src/cs_qr.c +94/−0
- igraph/src/cs_qrsol.c +73/−0
- igraph/src/cs_randperm.c +47/−0
- igraph/src/cs_reach.c +39/−0
- igraph/src/cs_scatter.c +42/−0
- igraph/src/cs_scc.c +61/−0
- igraph/src/cs_schol.c +46/−0
- igraph/src/cs_spsolve.c +48/−0
- igraph/src/cs_sqr.c +108/−0
- igraph/src/cs_symperm.c +59/−0
- igraph/src/cs_tdfs.c +44/−0
- igraph/src/cs_transpose.c +45/−0
- igraph/src/cs_updown.c +68/−0
- igraph/src/cs_usolve.c +38/−0
- igraph/src/cs_util.c +139/−0
- igraph/src/cs_utsolve.c +38/−0
- igraph/src/ctype.c +2/−0
- igraph/src/d_abs.c +18/−0
- igraph/src/d_acos.c +19/−0
- igraph/src/d_asin.c +19/−0
- igraph/src/d_atan.c +19/−0
- igraph/src/d_atn2.c +19/−0
- igraph/src/d_cnjg.c +19/−0
- igraph/src/d_cos.c +19/−0
- igraph/src/d_cosh.c +19/−0
- igraph/src/d_dim.c +16/−0
- igraph/src/d_exp.c +19/−0
- igraph/src/d_imag.c +16/−0
- igraph/src/d_int.c +19/−0
- igraph/src/d_lg10.c +21/−0
- igraph/src/d_log.c +19/−0
- igraph/src/d_mod.c +46/−0
- igraph/src/d_nint.c +20/−0
- igraph/src/d_prod.c +16/−0
- igraph/src/d_sign.c +18/−0
- igraph/src/d_sin.c +19/−0
- igraph/src/d_sinh.c +19/−0
- igraph/src/d_sqrt.c +19/−0
- igraph/src/d_tan.c +19/−0
- igraph/src/d_tanh.c +19/−0
- igraph/src/dasum.c +89/−0
- igraph/src/daxpy.c +97/−0
- igraph/src/dcopy.c +97/−0
- igraph/src/ddot.c +99/−0
- igraph/src/decomposition.c +471/−0
- igraph/src/defs.cc +42/−0
- igraph/src/degree_sequence.cpp +490/−0
- igraph/src/derf_.c +18/−0
- igraph/src/derfc_.c +20/−0
- igraph/src/dfe.c +151/−0
- igraph/src/dgebak.c +301/−0
- igraph/src/dgebal.c +466/−0
- igraph/src/dgeev.c +644/−0
- igraph/src/dgeevx.c +811/−0
- igraph/src/dgehd2.c +255/−0
- igraph/src/dgehrd.c +406/−0
- igraph/src/dgemm.c +378/−0
- igraph/src/dgemv.c +302/−0
- igraph/src/dgeqr2.c +220/−0
- igraph/src/dger.c +185/−0
- igraph/src/dgesv.c +201/−0
- igraph/src/dgetf2.c +244/−0
- igraph/src/dgetrf.c +270/−0
- igraph/src/dgetrs.c +246/−0
- igraph/src/dgetv0.c +480/−0
- igraph/src/dhseqr.c +574/−0
- igraph/src/disnan.c +95/−0
- igraph/src/distances.c +211/−0
- igraph/src/dlabad.c +118/−0
- igraph/src/dlacn2.c +332/−0
- igraph/src/dlacpy.c +182/−0
- igraph/src/dladiv.c +246/−0
- igraph/src/dlae2.c +196/−0
- igraph/src/dlaebz.c +727/−0
- igraph/src/dlaev2.c +249/−0
- igraph/src/dlaexc.c +524/−0
- igraph/src/dlagtf.c +285/−0
- igraph/src/dlagts.c +415/−0
- igraph/src/dlahqr.c +711/−0
- igraph/src/dlahr2.c +392/−0
- igraph/src/dlaisnan.c +107/−0
- igraph/src/dlaln2.c +658/−0
- igraph/src/dlamch.c +204/−0
- igraph/src/dlaneg.c +269/−0
- igraph/src/dlange.c +254/−0
- igraph/src/dlanhs.c +257/−0
- igraph/src/dlanst.c +215/−0
- igraph/src/dlansy.c +293/−0
- igraph/src/dlanv2.c +310/−0
- igraph/src/dlapy2.c +116/−0
- igraph/src/dlaqr0.c +849/−0
- igraph/src/dlaqr1.c +198/−0
- igraph/src/dlaqr2.c +821/−0
- igraph/src/dlaqr3.c +840/−0
- igraph/src/dlaqr4.c +844/−0
- igraph/src/dlaqr5.c +1148/−0
- igraph/src/dlaqrb.c +602/−0
- igraph/src/dlaqtr.c +898/−0
- igraph/src/dlar1v.c +545/−0
- igraph/src/dlarf.c +255/−0
- igraph/src/dlarfb.c +838/−0
- igraph/src/dlarfg.c +217/−0
- igraph/src/dlarft.c +438/−0
- igraph/src/dlarfx.c +790/−0
- igraph/src/dlarnv.c +193/−0
- igraph/src/dlarra.c +219/−0
- igraph/src/dlarrb.c +439/−0
- igraph/src/dlarrc.c +255/−0
- igraph/src/dlarrd.c +912/−0
- igraph/src/dlarre.c +986/−0
- igraph/src/dlarrf.c +523/−0
- igraph/src/dlarrj.c +419/−0
- igraph/src/dlarrk.c +264/−0
- igraph/src/dlarrr.c +222/−0
- igraph/src/dlarrv.c +1105/−0
- igraph/src/dlartg.c +235/−0
- igraph/src/dlaruv.c +236/−0
- igraph/src/dlascl.c +419/−0
- igraph/src/dlaset.c +211/−0
- igraph/src/dlasq2.c +688/−0
- igraph/src/dlasq3.c +453/−0
- igraph/src/dlasq4.c +484/−0
- igraph/src/dlasq5.c +462/−0
- igraph/src/dlasq6.c +271/−0
- igraph/src/dlasr.c +512/−0
- igraph/src/dlasrt.c +330/−0
- igraph/src/dlassq.c +168/−0
- igraph/src/dlaswp.c +222/−0
- igraph/src/dlasy2.c +557/−0
- igraph/src/dlatrd.c +418/−0
- igraph/src/dmout.c +393/−0
- igraph/src/dnaitr.c +950/−0
- igraph/src/dnapps.c +795/−0
- igraph/src/dnaup2.c +978/−0
- igraph/src/dnaupd.c +794/−0
- igraph/src/dnconv.c +178/−0
- igraph/src/dneigh.c +377/−0
- igraph/src/dneupd.c +1195/−0
- igraph/src/dngets.c +275/−0
- igraph/src/dnrm2.c +88/−0
- igraph/src/dolio.c +26/−0
- igraph/src/dorg2r.c +233/−0
- igraph/src/dorghr.c +277/−0
- igraph/src/dorgqr.c +341/−0
- igraph/src/dorm2l.c +301/−0
- igraph/src/dorm2r.c +305/−0
- igraph/src/dormhr.c +338/−0
- igraph/src/dormql.c +398/−0
- igraph/src/dormqr.c +398/−0
- igraph/src/dormtr.c +373/−0
- igraph/src/dotproduct.c +280/−0
- igraph/src/dpotf2.c +272/−0
- igraph/src/dpotrf.c +293/−0
- igraph/src/dqueue.c +55/−0
- igraph/src/drl_graph.cpp +1309/−0
- igraph/src/drl_graph_3d.cpp +877/−0
- igraph/src/drl_layout.cpp +476/−0
- igraph/src/drl_layout_3d.cpp +123/−0
- igraph/src/drl_parse.cpp +205/−0
- igraph/src/drot.c +81/−0
- igraph/src/dsaitr.c +950/−0
- igraph/src/dsapps.c +621/−0
- igraph/src/dsaup2.c +976/−0
- igraph/src/dsaupd.c +792/−0
- igraph/src/dscal.c +86/−0
- igraph/src/dsconv.c +168/−0
- igraph/src/dseigt.c +221/−0
- igraph/src/dsesrt.c +288/−0
- igraph/src/dseupd.c +1046/−0
- igraph/src/dsgets.c +259/−0
- igraph/src/dsortc.c +406/−0
- igraph/src/dsortr.c +268/−0
- igraph/src/dstatn.c +83/−0
- igraph/src/dstats.c +64/−0
- igraph/src/dstebz.c +867/−0
- igraph/src/dstein.c +525/−0
- igraph/src/dstemr.c +831/−0
- igraph/src/dsteqr.c +677/−0
- igraph/src/dsterf.c +510/−0
- igraph/src/dstqrb.c +691/−0
- igraph/src/dswap.c +104/−0
- igraph/src/dsyevr.c +759/−0
- igraph/src/dsymv.c +303/−0
- igraph/src/dsyr2.c +264/−0
- igraph/src/dsyr2k.c +396/−0
- igraph/src/dsyrk.c +361/−0
- igraph/src/dsytd2.c +366/−0
- igraph/src/dsytrd.c +428/−0
- igraph/src/dtime_.c +63/−0
- igraph/src/dtrevc.c +1306/−0
- igraph/src/dtrexc.c +468/−0
- igraph/src/dtrmm.c +442/−0
- igraph/src/dtrmv.c +335/−0
- igraph/src/dtrsen.c +623/−0
- igraph/src/dtrsm.c +479/−0
- igraph/src/dtrsna.c +696/−0
- igraph/src/dtrsv.c +335/−0
- igraph/src/dtrsyl.c +1389/−0
- igraph/src/due.c +77/−0
- igraph/src/dummy.c +2/−0
- igraph/src/dvout.c +276/−0
- igraph/src/ef1asc_.c +25/−0
- igraph/src/ef1cmc_.c +20/−0
- igraph/src/eigen.c +1520/−0
- igraph/src/embedding.c +1170/−0
- igraph/src/endfile.c +160/−0
- igraph/src/erf_.c +22/−0
- igraph/src/erfc_.c +22/−0
- igraph/src/err.c +293/−0
- igraph/src/error.c +74/−0
- igraph/src/etime_.c +57/−0
- igraph/src/exit_.c +43/−0
- igraph/src/f77_aloc.c +44/−0
- igraph/src/f77vers.c +97/−0
- igraph/src/fast_community.c +1067/−0
- igraph/src/feedback_arc_set.c +665/−0
- igraph/src/flow.c +2532/−0
- igraph/src/fmt.c +530/−0
- igraph/src/fmtlib.c +51/−0
- igraph/src/foreign-dl-lexer.c +2232/−0
- igraph/src/foreign-dl-parser.c +2145/−0
- igraph/src/foreign-gml-lexer.c +2055/−0
- igraph/src/foreign-gml-parser.c +1856/−0
- igraph/src/foreign-graphml.c +1846/−0
- igraph/src/foreign-lgl-lexer.c +2014/−0
- igraph/src/foreign-lgl-parser.c +1696/−0
- igraph/src/foreign-ncol-lexer.c +2010/−0
- igraph/src/foreign-ncol-parser.c +1685/−0
- igraph/src/foreign-pajek-lexer.c +2470/−0
- igraph/src/foreign-pajek-parser.c +2815/−0
- igraph/src/foreign.c +3390/−0
- igraph/src/forestfire.c +264/−0
- igraph/src/fortran_intrinsics.c +53/−0
- igraph/src/ftell_.c +52/−0
- igraph/src/games.c +4784/−0
- igraph/src/gengraph_box_list.cpp +108/−0
- igraph/src/gengraph_degree_sequence.cpp +420/−0
- igraph/src/gengraph_graph_molloy_hash.cpp +1173/−0
- igraph/src/gengraph_graph_molloy_optimized.cpp +2221/−0
- igraph/src/gengraph_mr-connected.cpp +186/−0
- igraph/src/gengraph_powerlaw.cpp +270/−0
- igraph/src/gengraph_random.cpp +278/−0
- igraph/src/getenv_.c +62/−0
- igraph/src/glet.c +870/−0
- igraph/src/glpk_support.c +101/−0
- igraph/src/gml_tree.c +261/−0
- igraph/src/graph.cc +5609/−0
- igraph/src/gss.c +154/−0
- igraph/src/h_abs.c +18/−0
- igraph/src/h_dim.c +16/−0
- igraph/src/h_dnnt.c +19/−0
- igraph/src/h_indx.c +32/−0
- igraph/src/h_len.c +16/−0
- igraph/src/h_mod.c +16/−0
- igraph/src/h_nint.c +19/−0
- igraph/src/h_sign.c +18/−0
- igraph/src/hacks.c +54/−0
- igraph/src/heap.c +1083/−0
- igraph/src/hl_ge.c +18/−0
- igraph/src/hl_gt.c +18/−0
- igraph/src/hl_le.c +18/−0
- igraph/src/hl_lt.c +18/−0
- igraph/src/i77vers.c +343/−0
- igraph/src/i_abs.c +18/−0
- igraph/src/i_dim.c +16/−0
- igraph/src/i_dnnt.c +19/−0
- igraph/src/i_indx.c +32/−0
- igraph/src/i_len.c +16/−0
- igraph/src/i_mod.c +16/−0
- igraph/src/i_nint.c +19/−0
- igraph/src/i_sign.c +18/−0
- igraph/src/idamax.c +82/−0
- igraph/src/ieeeck.c +218/−0
- igraph/src/igraph_buckets.c +198/−0
- igraph/src/igraph_cliquer.c +399/−0
- igraph/src/igraph_error.c +290/−0
- igraph/src/igraph_estack.c +67/−0
- igraph/src/igraph_fixed_vectorlist.c +80/−0
- igraph/src/igraph_grid.c +543/−0
- igraph/src/igraph_hashtable.c +128/−0
- igraph/src/igraph_heap.c +64/−0
- igraph/src/igraph_hrg.cc +1074/−0
- igraph/src/igraph_hrg_types.cc +3725/−0
- igraph/src/igraph_marked_queue.c +115/−0
- igraph/src/igraph_psumtree.c +102/−0
- igraph/src/igraph_set.c +320/−0
- igraph/src/igraph_stack.c +89/−0
- igraph/src/igraph_strvector.c +592/−0
- igraph/src/igraph_trie.c +391/−0
- igraph/src/iio.c +159/−0
- igraph/src/iladlc.c +134/−0
- igraph/src/iladlr.c +135/−0
- igraph/src/ilaenv.c +714/−0
- igraph/src/ilnw.c +83/−0
- igraph/src/infomap.cc +322/−0
- igraph/src/infomap_FlowGraph.cc +420/−0
- igraph/src/infomap_Greedy.cc +612/−0
- igraph/src/infomap_Node.cc +70/−0
- igraph/src/inquire.c +117/−0
- igraph/src/interrupt.c +46/−0
- igraph/src/iparmq.c +345/−0
- igraph/src/iterators.c +1917/−0
- igraph/src/ivout.c +278/−0
- igraph/src/kolmogorov.c +66/−0
- igraph/src/l_ge.c +18/−0
- igraph/src/l_gt.c +18/−0
- igraph/src/l_le.c +18/−0
- igraph/src/l_lt.c +18/−0
- igraph/src/lad.c +1665/−0
- igraph/src/lapack.c +954/−0
- igraph/src/layout.c +2421/−0
- igraph/src/layout_dh.c +457/−0
- igraph/src/layout_fr.c +700/−0
- igraph/src/layout_gem.c +246/−0
- igraph/src/layout_kk.c +680/−0
- igraph/src/lbfgs.c +1378/−0
- igraph/src/lbitbits.c +68/−0
- igraph/src/lbitshft.c +17/−0
- igraph/src/len_trim.c +36/−0
- igraph/src/lread.c +806/−0
- igraph/src/lsame.c +111/−0
- igraph/src/lsap.c +632/−0
- igraph/src/lwrite.c +314/−0
- igraph/src/matching.c +1025/−0
- igraph/src/math.c +326/−0
- igraph/src/matrix.c +158/−0
- igraph/src/maximal_cliques.c +496/−0
- igraph/src/memory.c +99/−0
- igraph/src/microscopic_update.c +1209/−0
- igraph/src/mixing.c +300/−0
- igraph/src/motifs.c +1126/−0
- igraph/src/open.c +301/−0
- igraph/src/operators.c +1243/−0
- igraph/src/optimal_modularity.c +260/−0
- igraph/src/options.c +47/−0
- igraph/src/orbit.cc +144/−0
- igraph/src/other.c +427/−0
- igraph/src/partition.cc +1143/−0
- igraph/src/paths.c +175/−0
- igraph/src/plfit.c +778/−0
- igraph/src/pottsmodel_2.cpp +2225/−0
- igraph/src/pow_ci.c +26/−0
- igraph/src/pow_dd.c +19/−0
- igraph/src/pow_di.c +41/−0
- igraph/src/pow_hh.c +39/−0
- igraph/src/pow_ii.c +39/−0
- igraph/src/pow_ri.c +41/−0
- igraph/src/pow_zi.c +60/−0
- igraph/src/pow_zz.c +29/−0
- igraph/src/progress.c +153/−0
- igraph/src/prpack.cpp +103/−0
- igraph/src/prpack_base_graph.cpp +333/−0
- igraph/src/prpack_igraph_graph.cpp +146/−0
- igraph/src/prpack_preprocessed_ge_graph.cpp +64/−0
- igraph/src/prpack_preprocessed_gs_graph.cpp +81/−0
- igraph/src/prpack_preprocessed_scc_graph.cpp +202/−0
- igraph/src/prpack_preprocessed_schur_graph.cpp +121/−0
- igraph/src/prpack_result.cpp +12/−0
- igraph/src/prpack_solver.cpp +878/−0
- igraph/src/prpack_utils.cpp +60/−0
- igraph/src/qsort.c +209/−0
- igraph/src/qsort_r.c +8/−0
- igraph/src/r_abs.c +18/−0
- igraph/src/r_acos.c +19/−0
- igraph/src/r_asin.c +19/−0
- igraph/src/r_atan.c +19/−0
- igraph/src/r_atn2.c +19/−0
- igraph/src/r_cnjg.c +18/−0
- igraph/src/r_cos.c +19/−0
- igraph/src/r_cosh.c +19/−0
- igraph/src/r_dim.c +16/−0
- igraph/src/r_exp.c +19/−0
- igraph/src/r_imag.c +16/−0
- igraph/src/r_int.c +19/−0
- igraph/src/r_lg10.c +21/−0
- igraph/src/r_log.c +19/−0
- igraph/src/r_mod.c +46/−0
- igraph/src/r_nint.c +20/−0
- igraph/src/r_sign.c +18/−0
- igraph/src/r_sin.c +19/−0
- igraph/src/r_sinh.c +19/−0
- igraph/src/r_sqrt.c +19/−0
- igraph/src/r_tan.c +19/−0
- igraph/src/r_tanh.c +19/−0
- igraph/src/random.c +2500/−0
- igraph/src/random_walk.c +287/−0
- igraph/src/rdfmt.c +553/−0
- igraph/src/reorder.c +425/−0
- igraph/src/rewind.c +30/−0
- igraph/src/rsfe.c +91/−0
- igraph/src/rsli.c +109/−0
- igraph/src/rsne.c +618/−0
- igraph/src/s_cat.c +86/−0
- igraph/src/s_cmp.c +50/−0
- igraph/src/s_copy.c +57/−0
- igraph/src/s_paus.c +96/−0
- igraph/src/s_rnge.c +32/−0
- igraph/src/s_stop.c +48/−0
- igraph/src/sbm.c +607/−0
- igraph/src/scan.c +880/−0
- igraph/src/scg.c +2292/−0
- igraph/src/scg_approximate_methods.c +173/−0
- igraph/src/scg_exact_scg.c +68/−0
- igraph/src/scg_kmeans.c +105/−0
- igraph/src/scg_optimal_method.c +241/−0
- igraph/src/scg_utils.c +94/−0
- igraph/src/second.c +42/−0
- igraph/src/separators.c +836/−0
- igraph/src/sfe.c +47/−0
- igraph/src/sig_die.c +51/−0
- igraph/src/signal_.c +21/−0
- igraph/src/signbit.c +24/−0
- igraph/src/sir.c +263/−0
- igraph/src/spanning_trees.c +521/−0
- igraph/src/sparsemat.c +3055/−0
- igraph/src/spectral_properties.c +436/−0
- igraph/src/spmatrix.c +1053/−0
- igraph/src/st-cuts.c +1549/−0
- igraph/src/statusbar.c +130/−0
- igraph/src/structural_properties.c +7238/−0
- igraph/src/structure_generators.c +2443/−0
- igraph/src/sue.c +90/−0
- igraph/src/sugiyama.c +1340/−0
- igraph/src/system_.c +42/−0
- igraph/src/topology.c +3129/−0
- igraph/src/triangles.c +978/−0
- igraph/src/type_indexededgelist.c +1706/−0
- igraph/src/types.c +146/−0
- igraph/src/typesize.c +18/−0
- igraph/src/uintseqhash.cc +117/−0
- igraph/src/uio.c +75/−0
- igraph/src/uninit.c +463/−0
- igraph/src/util.c +57/−0
- igraph/src/utils.cc +122/−0
- igraph/src/vector.c +466/−0
- igraph/src/vector_ptr.c +628/−0
- igraph/src/version.c +67/−0
- igraph/src/visitors.c +593/−0
- igraph/src/walktrap.cpp +174/−0
- igraph/src/walktrap_communities.cpp +937/−0
- igraph/src/walktrap_graph.cpp +254/−0
- igraph/src/walktrap_heap.cpp +245/−0
- igraph/src/wref.c +294/−0
- igraph/src/wrtfmt.c +377/−0
- igraph/src/wsfe.c +78/−0
- igraph/src/wsle.c +42/−0
- igraph/src/wsne.c +32/−0
- igraph/src/xerbla.c +129/−0
- igraph/src/xwsne.c +77/−0
- igraph/src/z_abs.c +18/−0
- igraph/src/z_cos.c +21/−0
- igraph/src/z_div.c +50/−0
- igraph/src/z_exp.c +23/−0
- igraph/src/z_log.c +121/−0
- igraph/src/z_sin.c +21/−0
- igraph/src/z_sqrt.c +35/−0
- igraph/src/zeroin.c +203/−0
- igraph/src/zeta.c +154/−0
- include/bytestring.h +1/−1
- include/haskell_attributes.h +1/−1
- include/haskell_igraph.h +1/−1
- src/IGraph/Algorithms.hs +2/−2
- src/IGraph/Algorithms/Generators.chs +9/−4
- src/IGraph/Algorithms/Layout.chs +0/−113
- src/IGraph/Exporter/GEXF.hs +0/−129
- src/IGraph/Exporter/Graphics.hs +0/−49
- src/IGraph/Internal.chs +43/−1
- src/IGraph/Internal/Constants.chs +1/−1
- src/IGraph/Random.hs +22/−0
- stack.yaml +4/−0
- tests/Test/Algorithms.hs +2/−1
- tests/Test/Attributes.hs +2/−2
- tests/Test/Basic.hs +18/−0
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 <- 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(&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(&vs, 0, IGRAPH_ALL);+ * igraph_vit_create(&graph, vs, &vit);+ * while (!IGRAPH_VIT_END(vit)) {+ * printf(" %li", (long int) IGRAPH_VIT_GET(vit));+ * IGRAPH_VIT_NEXT(vit);+ * }+ * printf("\n");+ * ...+ * igraph_vit_destroy(&vit);+ * igraph_vs_destroy(&vs);+ * </programlisting></informalexample>+ * </para>+ */++/**+ * \define IGRAPH_VIT_NEXT+ * \brief Next vertex.+ *+ * Steps the iterator to the next vertex. Only call this function if+ * \ref IGRAPH_VIT_END() returns false.+ * \param vit The vertex iterator to step.+ *+ * Time complexity: O(1).+ */+#define IGRAPH_VIT_NEXT(vit) (++((vit).pos))+/**+ * \define IGRAPH_VIT_END+ * \brief Are we at the end?+ *+ * Checks whether there are more vertices to step to.+ * \param vit The vertex iterator to check.+ * \return Logical value, if true there are no more vertices to step+ * to.+ *+ * Time complexity: O(1).+ */+#define IGRAPH_VIT_END(vit) ((vit).pos >= (vit).end)+/**+ * \define IGRAPH_VIT_SIZE+ * \brief Size of a vertex iterator.+ *+ * Gives the number of vertices in a vertex iterator.+ * \param vit The vertex iterator.+ * \return The number of vertices.+ *+ * Time complexity: O(1).+ */+#define IGRAPH_VIT_SIZE(vit) ((vit).end - (vit).start)+/**+ * \define IGRAPH_VIT_RESET+ * \brief Reset a vertex iterator.+ *+ * Resets a vertex iterator. After calling this macro the iterator+ * will point to the first vertex.+ * \param vit The vertex iterator.+ *+ * Time complexity: O(1).+ */+#define IGRAPH_VIT_RESET(vit) ((vit).pos = (vit).start)+/**+ * \define IGRAPH_VIT_GET+ * \brief Query the current position.+ *+ * Gives the vertex id of the current vertex pointed to by the+ * iterator.+ * \param vit The vertex iterator.+ * \return The vertex id of the current vertex.+ *+ * Time complexity: O(1).+ */+#define IGRAPH_VIT_GET(vit) \+ ((igraph_integer_t)(((vit).type == IGRAPH_VIT_SEQ) ? (vit).pos : \+ VECTOR(*(vit).vec)[(vit).pos]))++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(°ree, no_of_nodes);++IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL,+ IGRAPH_LOOPS));+maxdegree = (long int) igraph_vector_max(°ree) + 1;+igraph_vector_order1_int(°ree, &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(°ree);+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(&v, 5, 1,2,3,4,5); \endverbatim+ * is an error at runtime and the results are undefined. This is+ * the proper way:+ * \verbatim igraph_vector_t v;+ * igraph_vector_init_real(&v, 5, 1.0,2.0,3.0,4.0,5.0); \endverbatim+ * \param v Pointer to an uninitialized \type igraph_vector_t object.+ * \param no Positive integer, the number of \type igraph_real_t+ * parameters to follow.+ * \param ... The elements of the vector.+ * \return Error code, this can be \c IGRAPH_ENOMEM+ * if there isn't enough memory to allocate the vector.+ *+ * \sa \ref igraph_vector_init_real_end(), \ref igraph_vector_init_int() for similar+ * functions.+ *+ * Time complexity: depends on the time required to allocate memory,+ * but at least O(n), the number of+ * elements in the vector.+ */++int FUNCTION(igraph_vector, init_real)(TYPE(igraph_vector) *v, int no, ...) {+ int i = 0;+ va_list ap;+ IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, no));++ va_start(ap, no);+ for (i = 0; i < no; i++) {+ VECTOR(*v)[i] = (BASE) va_arg(ap, double);+ }+ va_end(ap);++ return 0;+}++/**+ * \ingroup vector+ * \function igraph_vector_init_real_end+ * \brief Create an \type igraph_vector_t from the parameters.+ *+ * </para><para>+ * This constructor is similar to \ref igraph_vector_init_real(), the only+ * difference is that instead of giving the number of elements in the+ * vector, a special marker element follows the last real vector+ * element.+ * \param v Pointer to an uninitialized \type igraph_vector_t object.+ * \param endmark This element will signal the end of the vector. It+ * will \em not be part of the vector.+ * \param ... The elements of the vector.+ * \return Error code, \c IGRAPH_ENOMEM if there+ * isn't enough memory.+ *+ * \sa \ref igraph_vector_init_real() and \ref igraph_vector_init_int_end() for+ * similar functions.+ *+ * Time complexity: at least O(n) for+ * n elements plus the time+ * complexity of the memory allocation.+ */++int FUNCTION(igraph_vector, init_real_end)(TYPE(igraph_vector) *v,+ BASE endmark, ...) {+ int i = 0, n = 0;+ va_list ap;++ va_start(ap, endmark);+ while (1) {+ BASE num = (BASE) va_arg(ap, double);+ if (num == endmark) {+ break;+ }+ n++;+ }+ va_end(ap);++ IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, n));+ IGRAPH_FINALLY(FUNCTION(igraph_vector, destroy), v);++ va_start(ap, endmark);+ for (i = 0; i < n; i++) {+ VECTOR(*v)[i] = (BASE) va_arg(ap, double);+ }+ va_end(ap);++ IGRAPH_FINALLY_CLEAN(1);+ return 0;+}++/**+ * \ingroup vector+ * \function igraph_vector_init_int+ * \brief Create an \type igraph_vector_t containing the parameters.+ *+ * </para><para>+ * This function is similar to \ref igraph_vector_init_real(), but it expects+ * \type int parameters. It is important that all parameters+ * should be of this type, otherwise the result of the function call+ * is undefined.+ * \param v Pointer to an uninitialized \type igraph_vector_t object.+ * \param no The number of \type int parameters to follow.+ * \param ... The elements of the vector.+ * \return Error code, \c IGRAPH_ENOMEM if there is+ * not enough memory.+ * \sa \ref igraph_vector_init_real() and igraph_vector_init_int_end(), these are+ * similar functions.+ *+ * Time complexity: at least O(n) for+ * n elements plus the time+ * complexity of the memory allocation.+ */++int FUNCTION(igraph_vector, init_int)(TYPE(igraph_vector) *v, int no, ...) {+ int i = 0;+ va_list ap;+ IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, no));++ va_start(ap, no);+ for (i = 0; i < no; i++) {+ VECTOR(*v)[i] = (BASE) va_arg(ap, int);+ }+ va_end(ap);++ return 0;+}++/**+ * \ingroup vector+ * \function igraph_vector_init_int_end+ * \brief Create an \type igraph_vector_t from the parameters.+ *+ * </para><para>+ * This constructor is similar to \ref igraph_vector_init_int(), the only+ * difference is that instead of giving the number of elements in the+ * vector, a special marker element follows the last real vector+ * element.+ * \param v Pointer to an uninitialized \type igraph_vector_t object.+ * \param endmark This element will signal the end of the vector. It+ * will \em not be part of the vector.+ * \param ... The elements of the vector.+ * \return Error code, \c IGRAPH_ENOMEM if there+ * isn't enough memory.+ *+ * \sa \ref igraph_vector_init_int() and \ref igraph_vector_init_real_end() for+ * similar functions.+ *+ * Time complexity: at least O(n) for+ * n elements plus the time+ * complexity of the memory allocation.+ */++int FUNCTION(igraph_vector_init, int_end)(TYPE(igraph_vector) *v, int endmark, ...) {+ int i = 0, n = 0;+ va_list ap;++ va_start(ap, endmark);+ while (1) {+ int num = va_arg(ap, int);+ if (num == endmark) {+ break;+ }+ n++;+ }+ va_end(ap);++ IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, n));+ IGRAPH_FINALLY(FUNCTION(igraph_vector, destroy), v);++ va_start(ap, endmark);+ for (i = 0; i < n; i++) {+ VECTOR(*v)[i] = (BASE) va_arg(ap, int);+ }+ va_end(ap);++ IGRAPH_FINALLY_CLEAN(1);+ return 0;+}++#endif /* ifndef BASE_COMPLEX */++/**+ * \ingroup vector+ * \function igraph_vector_destroy+ * \brief Destroys a vector object.+ *+ * </para><para>+ * All vectors initialized by \ref igraph_vector_init() should be properly+ * destroyed by this function. A destroyed vector needs to be+ * reinitialized by \ref igraph_vector_init(), \ref igraph_vector_init_copy() or+ * another constructor.+ * \param v Pointer to the (previously initialized) vector object to+ * destroy.+ *+ * Time complexity: operating system dependent.+ */++void FUNCTION(igraph_vector, destroy) (TYPE(igraph_vector)* v) {+ assert(v != 0);+ if (v->stor_begin != 0) {+ igraph_Free(v->stor_begin);+ v->stor_begin = NULL;+ }+}++/**+ * \ingroup vector+ * \function igraph_vector_capacity+ * \brief Returns the allocated capacity of the vector+ *+ * Note that this might be different from the size of the vector (as+ * queried by \ref igraph_vector_size(), and specifies how many elements+ * the vector can hold, without reallocation.+ * \param v Pointer to the (previously initialized) vector object+ * to query.+ * \return The allocated capacity.+ *+ * \sa \ref igraph_vector_size().+ *+ * Time complexity: O(1).+ */++long int FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector)*v) {+ return v->stor_end - v->stor_begin;+}++/**+ * \ingroup vector+ * \function igraph_vector_reserve+ * \brief Reserves memory for a vector.+ *+ * </para><para>+ * \a igraph vectors are flexible, they can grow and+ * shrink. Growing+ * however occasionally needs the data in the vector to be copied.+ * In order to avoid this, you can call this function to reserve space for+ * future growth of the vector.+ *+ * </para><para>+ * Note that this function does \em not change the size of the+ * vector. Let us see a small example to clarify things: if you+ * reserve space for 100 elements and the size of your+ * vector was (and still is) 60, then you can surely add additional 40+ * elements to your vector before it will be copied.+ * \param v The vector object.+ * \param size The new \em allocated size of the vector.+ * \return Error code:+ * \c IGRAPH_ENOMEM if there is not enough memory.+ *+ * Time complexity: operating system dependent, should be around+ * O(n), n+ * is the new allocated size of the vector.+ */++int FUNCTION(igraph_vector, reserve) (TYPE(igraph_vector)* v, long int size) {+ long int actual_size = FUNCTION(igraph_vector, size)(v);+ BASE *tmp;+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ if (size <= FUNCTION(igraph_vector, size)(v)) {+ return 0;+ }++ tmp = igraph_Realloc(v->stor_begin, (size_t) size, BASE);+ if (tmp == 0) {+ IGRAPH_ERROR("cannot reserve space for vector", IGRAPH_ENOMEM);+ }+ v->stor_begin = tmp;+ v->stor_end = v->stor_begin + size;+ v->end = v->stor_begin + actual_size;++ return 0;+}++/**+ * \ingroup vector+ * \function igraph_vector_empty+ * \brief Decides whether the size of the vector is zero.+ *+ * \param v The vector object.+ * \return Non-zero number (true) if the size of the vector is zero and+ * zero (false) otherwise.+ *+ * Time complexity: O(1).+ */++igraph_bool_t FUNCTION(igraph_vector, empty) (const TYPE(igraph_vector)* v) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ return v->stor_begin == v->end;+}++/**+ * \ingroup vector+ * \function igraph_vector_size+ * \brief Gives the size (=length) of the vector.+ *+ * \param v The vector object+ * \return The size of the vector.+ *+ * Time complexity: O(1).+ */++long int FUNCTION(igraph_vector, size) (const TYPE(igraph_vector)* v) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ return v->end - v->stor_begin;+}++/**+ * \ingroup vector+ * \function igraph_vector_clear+ * \brief Removes all elements from a vector.+ *+ * </para><para>+ * This function simply sets the size of the vector to zero, it does+ * not free any allocated memory. For that you have to call+ * \ref igraph_vector_destroy().+ * \param v The vector object.+ *+ * Time complexity: O(1).+ */++void FUNCTION(igraph_vector, clear) (TYPE(igraph_vector)* v) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ v->end = v->stor_begin;+}++/**+ * \ingroup vector+ * \function igraph_vector_push_back+ * \brief Appends one element to a vector.+ *+ * </para><para>+ * This function resizes the vector to be one element longer and+ * sets the very last element in the vector to \p e.+ * \param v The vector object.+ * \param e The element to append to the vector.+ * \return Error code:+ * \c IGRAPH_ENOMEM: not enough memory.+ *+ * Time complexity: operating system dependent. What is important is that+ * a sequence of n+ * subsequent calls to this function has time complexity+ * O(n), even if there+ * hadn't been any space reserved for the new elements by+ * \ref igraph_vector_reserve(). This is implemented by a trick similar to the C+++ * \type vector class: each time more memory is allocated for a+ * vector, the size of the additionally allocated memory is the same+ * as the vector's current length. (We assume here that the time+ * complexity of memory allocation is at most linear.)+ */++int FUNCTION(igraph_vector, push_back) (TYPE(igraph_vector)* v, BASE e) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);++ /* full, allocate more storage */+ if (v->stor_end == v->end) {+ long int new_size = FUNCTION(igraph_vector, size)(v) * 2;+ if (new_size == 0) {+ new_size = 1;+ }+ IGRAPH_CHECK(FUNCTION(igraph_vector, reserve)(v, new_size));+ }++ *(v->end) = e;+ v->end += 1;++ return 0;+}++/**+ * \ingroup vector+ * \function igraph_vector_insert+ * \brief Inserts a single element into a vector.+ *+ * Note that this function does not do range checking. Insertion will shift the+ * elements from the position given to the end of the vector one position to the+ * right, and the new element will be inserted in the empty space created at+ * the given position. The size of the vector will increase by one.+ *+ * \param v The vector object.+ * \param pos The position where the new element is to be inserted.+ * \param value The new element to be inserted.+ */+int FUNCTION(igraph_vector, insert)(TYPE(igraph_vector) *v, long int pos,+ BASE value) {+ size_t size = (size_t) FUNCTION(igraph_vector, size)(v);+ IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(v, (long) size + 1));+ if (pos < size) {+ memmove(v->stor_begin + pos + 1, v->stor_begin + pos,+ sizeof(BASE) * (size - (size_t) pos));+ }+ v->stor_begin[pos] = value;+ return 0;+}++/**+ * \ingroup vector+ * \section igraph_vector_accessing_elements Accessing elements+ *+ * <para>The simplest way to access an element of a vector is to use the+ * \ref VECTOR macro. This macro can be used both for querying and setting+ * \type igraph_vector_t elements. If you need a function, \ref+ * igraph_vector_e() queries and \ref igraph_vector_set() sets an element of a+ * vector. \ref igraph_vector_e_ptr() returns the address of an element.</para>+ *+ * <para>\ref igraph_vector_tail() returns the last element of a non-empty+ * vector. There is no <function>igraph_vector_head()</function> function+ * however, as it is easy to write <code>VECTOR(v)[0]</code>+ * instead.</para>+ */++/**+ * \ingroup vector+ * \function igraph_vector_e+ * \brief Access an element of a vector.+ * \param v The \type igraph_vector_t object.+ * \param pos The position of the element, the index of the first+ * element is zero.+ * \return The desired element.+ * \sa \ref igraph_vector_e_ptr() and the \ref VECTOR macro.+ *+ * Time complexity: O(1).+ */++BASE FUNCTION(igraph_vector, e) (const TYPE(igraph_vector)* v, long int pos) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ return * (v->stor_begin + pos);+}++/**+ * \ingroup vector+ * \function igraph_vector_e_ptr+ * \brief Get the address of an element of a vector+ * \param v The \type igraph_vector_t object.+ * \param pos The position of the element, the position of the first+ * element is zero.+ * \return Pointer to the desired element.+ * \sa \ref igraph_vector_e() and the \ref VECTOR macro.+ *+ * Time complexity: O(1).+ */++BASE* FUNCTION(igraph_vector, e_ptr) (const TYPE(igraph_vector)* v, long int pos) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ return v->stor_begin + pos;+}++/**+ * \ingroup vector+ * \function igraph_vector_set+ * \brief Assignment to an element of a vector.+ * \param v The \type igraph_vector_t element.+ * \param pos Position of the element to set.+ * \param value New value of the element.+ * \sa \ref igraph_vector_e().+ */++void FUNCTION(igraph_vector, set) (TYPE(igraph_vector)* v,+ long int pos, BASE value) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ *(v->stor_begin + pos) = value;+}++/**+ * \ingroup vector+ * \function igraph_vector_null+ * \brief Sets each element in the vector to zero.+ *+ * </para><para>+ * Note that \ref igraph_vector_init() sets the elements to zero as well, so+ * it makes no sense to call this function on a just initialized+ * vector. Thus if you want to construct a vector of zeros, then you should+ * use \ref igraph_vector_init().+ * \param v The vector object.+ *+ * Time complexity: O(n), the size of+ * the vector.+ */++void FUNCTION(igraph_vector, null) (TYPE(igraph_vector)* v) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ if (FUNCTION(igraph_vector, size)(v) > 0) {+ memset(v->stor_begin, 0,+ sizeof(BASE) * (size_t) FUNCTION(igraph_vector, size)(v));+ }+}++/**+ * \function igraph_vector_fill+ * \brief Fill a vector with a constant element+ *+ * Sets each element of the vector to the supplied constant.+ * \param vector The vector to work on.+ * \param e The element to fill with.+ *+ * Time complexity: O(n), the size of the vector.+ */++void FUNCTION(igraph_vector, fill) (TYPE(igraph_vector)* v, BASE e) {+ BASE *ptr;+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ for (ptr = v->stor_begin; ptr < v->end; ptr++) {+ *ptr = e;+ }+}++/**+ * \ingroup vector+ * \function igraph_vector_tail+ * \brief Returns the last element in a vector.+ *+ * </para><para>+ * It is an error to call this function on an empty vector, the result+ * is undefined.+ * \param v The vector object.+ * \return The last element.+ *+ * Time complexity: O(1).+ */++BASE FUNCTION(igraph_vector, tail)(const TYPE(igraph_vector) *v) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ return *((v->end) - 1);+}++/**+ * \ingroup vector+ * \function igraph_vector_pop_back+ * \brief Removes and returns the last element of a vector.+ *+ * </para><para>+ * It is an error to call this function with an empty vector.+ * \param v The vector object.+ * \return The removed last element.+ *+ * Time complexity: O(1).+ */++BASE FUNCTION(igraph_vector, pop_back)(TYPE(igraph_vector)* v) {+ BASE tmp;+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ assert(v->end != v->stor_begin);+ tmp = FUNCTION(igraph_vector, e)(v, FUNCTION(igraph_vector, size)(v) - 1);+ v->end -= 1;+ return tmp;+}++#ifndef NOTORDERED++/**+ * \ingroup vector+ * \function igraph_vector_sort_cmp+ * \brief Internal comparison function of vector elements, used by+ * \ref igraph_vector_sort().+ */++int FUNCTION(igraph_vector, sort_cmp)(const void *a, const void *b) {+ const BASE *da = (const BASE *) a;+ const BASE *db = (const BASE *) b;++ return (*da > *db) - (*da < *db);+}++/**+ * \ingroup vector+ * \function igraph_vector_sort+ * \brief Sorts the elements of the vector into ascending order.+ *+ * </para><para>+ * This function uses the built-in sort function of the C library.+ * \param v Pointer to an initialized vector object.+ *+ * Time complexity: should be+ * O(nlogn) for+ * n+ * elements.+ */++void FUNCTION(igraph_vector, sort)(TYPE(igraph_vector) *v) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ igraph_qsort(v->stor_begin, (size_t) FUNCTION(igraph_vector, size)(v),+ sizeof(BASE), FUNCTION(igraph_vector, sort_cmp));+}++/**+ * Ascending comparison function passed to qsort from igraph_vector_qsort_ind+ */+int FUNCTION(igraph_vector, i_qsort_ind_cmp_asc)(const void *p1, const void *p2) {+ BASE **pa = (BASE **) p1;+ BASE **pb = (BASE **) p2;+ if ( **pa < **pb ) {+ return -1;+ }+ if ( **pa > **pb) {+ return 1;+ }+ return 0;+}++/**+ * Descending comparison function passed to qsort from igraph_vector_qsort_ind+ */+int FUNCTION(igraph_vector, i_qsort_ind_cmp_desc)(const void *p1, const void *p2) {+ BASE **pa = (BASE **) p1;+ BASE **pb = (BASE **) p2;+ if ( **pa < **pb ) {+ return 1;+ }+ if ( **pa > **pb) {+ return -1;+ }+ return 0;+}++/**+ * \function igraph_vector_qsort_ind+ * \brief Return a permutation of indices that sorts a vector+ *+ * Takes an unsorted array \c v as input and computes an array of+ * indices inds such that v[ inds[i] ], with i increasing from 0, is+ * an ordered array (either ascending or descending, depending on+ * \v order). The order of indices for identical elements is not+ * defined.+ *+ * \param v the array to be sorted+ * \param inds the output array of indices. this must be initialized,+ * but will be resized+ * \param descending whether the output array should be sorted in descending+ * order.+ * \return Error code.+ *+ * This routine uses the C library qsort routine.+ * Algorithm: 1) create an array of pointers to the elements of v. 2)+ * Pass this array to qsort. 3) after sorting the difference between+ * the pointer value and the first pointer value gives its original+ * position in the array. Use this to set the values of inds.+ *+ * Some tests show that this routine is faster than+ * igraph_vector_heapsort_ind by about 10 percent+ * for small vectors to a factor of two for large vectors.+ */++long int FUNCTION(igraph_vector, qsort_ind)(TYPE(igraph_vector) *v,+ igraph_vector_t *inds, igraph_bool_t descending) {+ long int i;+ BASE **vind, *first;+ size_t n = (size_t) FUNCTION(igraph_vector, size)(v);+ IGRAPH_CHECK(igraph_vector_resize(inds, (long) n));+ if (n == 0) {+ return 0;+ }+ vind = igraph_Calloc(n, BASE*);+ if (vind == 0) {+ IGRAPH_ERROR("igraph_vector_qsort_ind failed", IGRAPH_ENOMEM);+ }+ for (i = 0; i < n; i++) {+ vind[i] = &VECTOR(*v)[i];+ }+ first = vind[0];+ if (descending) {+ igraph_qsort(vind, n, sizeof(BASE**), FUNCTION(igraph_vector, i_qsort_ind_cmp_desc));+ } else {+ igraph_qsort(vind, n, sizeof(BASE**), FUNCTION(igraph_vector, i_qsort_ind_cmp_asc));+ }+ for (i = 0; i < n; i++) {+ VECTOR(*inds)[i] = vind[i] - first;+ }+ igraph_Free(vind);+ return 0;+}++#endif++/**+ * \ingroup vector+ * \function igraph_vector_resize+ * \brief Resize the vector.+ *+ * </para><para>+ * Note that this function does not free any memory, just sets the+ * size of the vector to the given one. It can on the other hand+ * allocate more memory if the new size is larger than the previous+ * one. In this case the newly appeared elements in the vector are+ * \em not set to zero, they are uninitialized.+ * \param v The vector object+ * \param newsize The new size of the vector.+ * \return Error code,+ * \c IGRAPH_ENOMEM if there is not enough+ * memory. Note that this function \em never returns an error+ * if the vector is made smaller.+ * \sa \ref igraph_vector_reserve() for allocating memory for future+ * extensions of a vector. \ref igraph_vector_resize_min() for+ * deallocating the unnneded memory for a vector.+ *+ * Time complexity: O(1) if the new+ * size is smaller, operating system dependent if it is larger. In the+ * latter case it is usually around+ * O(n),+ * n is the new size of the vector.+ */++int FUNCTION(igraph_vector, resize)(TYPE(igraph_vector)* v, long int newsize) {+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ IGRAPH_CHECK(FUNCTION(igraph_vector, reserve)(v, newsize));+ v->end = v->stor_begin + newsize;+ return 0;+}++/**+ * \ingroup vector+ * \function igraph_vector_resize_min+ * \brief Deallocate the unused memory of a vector.+ *+ * </para><para>+ * Note that this function involves additional memory allocation and+ * may result an out-of-memory error.+ * \param v Pointer to an initialized vector.+ * \return Error code.+ *+ * \sa \ref igraph_vector_resize(), \ref igraph_vector_reserve().+ *+ * Time complexity: operating system dependent.+ */++int FUNCTION(igraph_vector, resize_min)(TYPE(igraph_vector)*v) {+ size_t size;+ BASE *tmp;+ if (v->stor_end == v->end) {+ return 0;+ }++ size = (size_t) (v->end - v->stor_begin);+ tmp = igraph_Realloc(v->stor_begin, size, BASE);+ if (tmp == 0) {+ IGRAPH_ERROR("cannot resize vector", IGRAPH_ENOMEM);+ } else {+ v->stor_begin = tmp;+ v->stor_end = v->end = v->stor_begin + size;+ }++ return 0;+}++#ifndef NOTORDERED++/**+ * \ingroup vector+ * \function igraph_vector_max+ * \brief Gives the maximum element of the vector.+ *+ * </para><para>+ * If the size of the vector is zero, an arbitrary number is+ * returned.+ * \param v The vector object.+ * \return The maximum element.+ *+ * Time complexity: O(n),+ * n is the size of the vector.+ */++BASE FUNCTION(igraph_vector, max)(const TYPE(igraph_vector)* v) {+ BASE max;+ BASE *ptr;+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ max = *(v->stor_begin);+ ptr = v->stor_begin + 1;+ while (ptr < v->end) {+ if ((*ptr) > max) {+ max = *ptr;+ }+ ptr++;+ }+ return max;+}++/**+ * \ingroup vector+ * \function igraph_vector_which_max+ * \brief Gives the position of the maximum element of the vector.+ *+ * </para><para>+ * If the size of the vector is zero, -1 is+ * returned.+ * \param v The vector object.+ * \return The position of the first maximum element.+ *+ * Time complexity: O(n),+ * n is the size of the vector.+ */++long int FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector)* v) {+ long int which = -1;+ if (!FUNCTION(igraph_vector, empty)(v)) {+ BASE max;+ BASE *ptr;+ long int pos;+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ max = *(v->stor_begin); which = 0;+ ptr = v->stor_begin + 1; pos = 1;+ while (ptr < v->end) {+ if ((*ptr) > max) {+ max = *ptr;+ which = pos;+ }+ ptr++; pos++;+ }+ }+ return which;+}++/**+ * \function igraph_vector_min+ * \brief Smallest element of a vector.+ *+ * The vector must be non-empty.+ * \param v The input vector.+ * \return The smallest element of \p v.+ *+ * Time complexity: O(n), the number of elements.+ */++BASE FUNCTION(igraph_vector, min)(const TYPE(igraph_vector)* v) {+ BASE min;+ BASE *ptr;+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ min = *(v->stor_begin);+ ptr = v->stor_begin + 1;+ while (ptr < v->end) {+ if ((*ptr) < min) {+ min = *ptr;+ }+ ptr++;+ }+ return min;+}++/**+ * \function igraph_vector_which_min+ * \brief Index of the smallest element.+ *+ * The vector must be non-empty.+ * If the smallest element is not unique, then the index of the first+ * is returned.+ * \param v The input vector.+ * \return Index of the smallest element.+ *+ * Time complexity: O(n), the number of elements.+ */++long int FUNCTION(igraph_vector, which_min)(const TYPE(igraph_vector)* v) {+ long int which = -1;+ if (!FUNCTION(igraph_vector, empty)(v)) {+ BASE min;+ BASE *ptr;+ long int pos;+ assert(v != NULL);+ assert(v->stor_begin != NULL);+ min = *(v->stor_begin); which = 0;+ ptr = v->stor_begin + 1; pos = 1;+ while (ptr < v->end) {+ if ((*ptr) < min) {+ min = *ptr;+ which = pos;+ }+ ptr++; pos++;+ }+ }+ return which;+}++#endif++/**+ * \ingroup vector+ * \function igraph_vector_init_copy+ * \brief Initializes a vector from an ordinary C array (constructor).+ *+ * \param v Pointer to an uninitialized vector object.+ * \param data A regular C array.+ * \param length The length of the C array.+ * \return Error code:+ * \c IGRAPH_ENOMEM if there is not enough memory.+ *+ * Time complexity: operating system specific, usually+ * O(\p length).+ */++int FUNCTION(igraph_vector, init_copy)(TYPE(igraph_vector) *v,+ 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 & 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 < 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(", &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(&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(°ree, options->n);+ IGRAPH_CHECK(igraph_degree(graph, °ree, 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(°ree);+ 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(°ree, 0));+ IGRAPH_FINALLY(igraph_vector_destroy, °ree);+ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL, 0));++ vertex = igraph_vector_which_max(°ree);+ maxdeg = VECTOR(degree)[vertex];++ igraph_vector_destroy(°ree);+ 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(°, no_of_nodes);+ if (!weights) {+ IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(), IGRAPH_ALL,+ IGRAPH_LOOPS));+ } else {+ IGRAPH_CHECK(igraph_strength(graph, °, 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(°);+ 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+ * & 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., & 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 & 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üfer sequence+ *+ * A Prü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ü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(°rees, n);+ IGRAPH_VECTOR_INIT_FINALLY(&neighbors, 1);++ IGRAPH_CHECK(igraph_degree(graph, °rees, 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(°rees);+ 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(°, 0);+ igraph_strength(graph, °, 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(°);+ 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=*/ °, /*deg2=*/ 0,+ options, callback, 0, /*symmetric=*/ 1,+ /*eigen=*/ 1, /*zapsmall=*/ 1));++ igraph_vector_destroy(°);+ 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(°_in, n);+ IGRAPH_VECTOR_INIT_FINALLY(°_out, n);+ igraph_strength(graph, °_in, igraph_vss_all(), IGRAPH_IN, /*loops=*/ 1,+ weights);+ igraph_strength(graph, °_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=*/ °_in,+ /*deg2=*/ °_out, options, callback,+ callback_right, /*symmetric=*/ 0, /*eigen=*/ 0,+ /*zapsmall=*/ 1));++ igraph_vector_destroy(°_in);+ igraph_vector_destroy(°_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(°rees, no_of_nodes);+ IGRAPH_VECTOR_INIT_FINALLY(&roots, no_of_nodes);++ IGRAPH_CHECK(igraph_strength(graph, °rees, igraph_vss_all(),+ IGRAPH_ALL, 0, weights));+ IGRAPH_CHECK((int) igraph_vector_qsort_ind(°rees, &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(°rees);+ 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), ¤t, &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, ¤t, &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(¤t, 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(¤t);+ 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(¤t);+ 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(°ree, 0);+ if (!igraph_is_directed(graph)) {+ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(),+ IGRAPH_OUT, IGRAPH_LOOPS));+ if (igraph_vector_min(°ree) == 1) {+ *res = 1;+ *found = 1;+ }+ } else {+ /* directed, check both in- & out-degree */+ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(),+ IGRAPH_OUT, IGRAPH_LOOPS));+ if (igraph_vector_min(°ree) == 1) {+ *res = 1;+ *found = 1;+ } else {+ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(),+ IGRAPH_IN, IGRAPH_LOOPS));+ if (igraph_vector_min(°ree) == 1) {+ *res = 1;+ *found = 1;+ }+ }+ }+ igraph_vector_destroy(°ree);+ 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, "&"); d += 4; break;+ case '<':+ strcpy(d, "<"); d += 3; break;+ case '>':+ strcpy(d, ">"); d += 3; break;+ case '"':+ strcpy(d, """); d += 5; break;+ case '\'':+ strcpy(d, "'"); d += 5; break;+ default:+ *d = 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(>ypes, 0);+ IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);+ IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);+ igraph_i_attribute_get_info(graph,+ &gnames, >ypes,+ &vnames, &vtypes,+ &enames, &etypes);++ /* graph attributes */+ for (i = 0; i < igraph_vector_size(>ypes); 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(>ypes); 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(>ypes);+ 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 = ≜+ 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 = ≜+ 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(°, 1);+ IGRAPH_CHECK(igraph_strvector_init(&nvec, 1));+ IGRAPH_FINALLY(igraph_strvector_destroy, &nvec);+ for (i = 0; i < nov; i++) {+ igraph_degree(graph, °, 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(°);+ 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(>ypes, 0);+ IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);+ IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);+ IGRAPH_CHECK(igraph_i_attribute_get_info(graph,+ &gnames, >ypes,+ &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(>ypes); 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(>ypes);+ 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(>ypes, 0);+ IGRAPH_VECTOR_INIT_FINALLY(&vtypes, 0);+ IGRAPH_VECTOR_INIT_FINALLY(&etypes, 0);+ IGRAPH_CHECK(igraph_i_attribute_get_info(graph,+ &gnames, >ypes,+ &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(>ypes) > 0) {+ CHECK(fprintf(outstream, " graph [\n"));+ for (i = 0; i < igraph_vector_size(>ypes); 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(>ypes);+ 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(°, sn);+ IGRAPH_CHECK(igraph_degree(start_from, °, 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(°);+ 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(°ree, 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, °ree, igraph_vss_all(), mm,+ IGRAPH_LOOPS));+ IGRAPH_CHECK(igraph_vector_resize(°ree, 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(°ree);+ 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(°ree, 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, °ree, igraph_vss_all(), mm,+ IGRAPH_LOOPS));+ IGRAPH_CHECK(igraph_vector_resize(°ree, 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(°ree);+ IGRAPH_FINALLY_CLEAN(2);++ IGRAPH_CHECK(igraph_create(graph, &edges, n, directed));+ igraph_vector_destroy(&edges);+ IGRAPH_FINALLY_CLEAN(1);++ return 0;+}++/**+ * \ingroup generators+ * \function igraph_barabasi_game+ * \brief Generates a graph based on the Barabási-Albert model.+ *+ * \param graph An uninitialized graph object.+ * \param n The number of vertices in the graph.+ * \param power Power of the preferential attachment. The probability+ * that a vertex is cited is proportional to d^power+A, where+ * d is its degree (see also the \p outpref argument), power+ * and A are given by arguments. In the classic preferential+ * attachment model power=1.+ * \param m The number of outgoing edges generated for each+ * vertex. (Only if \p outseq is \c NULL.)+ * \param outseq Gives the (out-)degrees of the vertices. If this is+ * constant, this can be a NULL pointer or an empty (but+ * initialized!) vector, in this case \p m contains+ * the constant out-degree. The very first vertex has by definition+ * no outgoing edges, so the first number in this vector is+ * ignored.+ * \param outpref Boolean, if true not only the in- but also the out-degree+ * of a vertex increases its citation probability. Ie. the+ * citation probability is determined by the total degree of+ * the vertices. 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, °seq_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, °seq_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, °_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, °seq_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, °seq_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<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(°ree, 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(°ree);+ 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(°ree, 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(°ree);+ 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(°ree, 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(°ree);+ 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(°seq, no_of_nodes);+ igraph_vector_fill(°seq, k);+ IGRAPH_CHECK(igraph_degree_sequence_game(graph, °seq, directed ? °seq : 0, mode));++ igraph_vector_destroy(°seq);+ 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ü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 °s) {+ 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 °s) {+ 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 °s) {+ 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 °s) {+ 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(°ree_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(°, 0);++ // Every vertex, except for the root must have in-degree one.+ IGRAPH_CHECK(igraph_degree(graph, °, 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, °, 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(°);+ 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 < 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 & 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, ¶m);+ } else {+ ls = linesearch(n, x, &fx, g, d, &step, xp, pg, w, &cd, ¶m);+ 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(°v, 1);+ IGRAPH_CHECK(igraph_degree(graph, °v, igraph_vss_1(vid),+ mode, IGRAPH_NO_LOOPS));+ if (VECTOR(degv)[0] < 1) {+ *updates = 0;+ }+ igraph_vector_destroy(°v);+ 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(°, 1);+ while (!IGRAPH_VIT_END(vA)) {+ u = (igraph_integer_t)IGRAPH_VIT_GET(vA);+ IGRAPH_CHECK(igraph_degree(graph, °, 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(°);+ igraph_vector_destroy(&V);+ igraph_vit_destroy(&vA);+ igraph_eit_destroy(&eA);+ igraph_vs_destroy(&vs);+ igraph_es_destroy(&es);+ IGRAPH_FINALLY_CLEAN(6);++ return IGRAPH_SUCCESS;+}++/**+ * \ingroup spatialgames+ * \function igraph_roulette_wheel_imitation+ * \brief Adopt a strategy via roulette wheel selection.+ *+ * A simple stochastic imitation strategy where a vertex revises its+ * strategy to that of a vertex u chosen proportionate to u's quantity+ * (e.g. fitness). This is a special case of stochastic imitation, where a+ * candidate is not chosen uniformly at random but proportionate to its+ * quantity.+ *+ * \param graph The graph object representing the game network. This cannot+ * be the empty or trivial graph, but must have at least two vertices+ * and one edge. If \p graph has one vertex, then no strategy update+ * would take place. Furthermore, if \p graph has at least two vertices+ * but zero edges, then strategy update would also not take place.+ * \param vid The vertex whose strategy is to be updated. It is assumed that+ * \p vid represents a vertex in \p graph. No checking is performed and+ * it is your responsibility to ensure that \p vid is indeed a vertex+ * of \p graph. If an isolated vertex is provided, i.e. the input+ * vertex has degree 0, then no strategy update would take place and+ * \p vid would retain its current strategy. Strategy update would also+ * not take place if the local neighbourhood of \p vid are its+ * in-neighbours (respectively out-neighbours), but \p vid has zero+ * in-neighbours (respectively out-neighbours). Loops are ignored in+ * computing the degree (in, out, all) of \p vid.+ * \param islocal Boolean; this flag controls which perspective to use in+ * computing the relative quantity. If true then we use the local+ * perspective; otherwise we use the global perspective. The local+ * perspective for \p vid is the set of all immediate neighbours of+ * \p vid. In contrast, the global perspective for \p vid is the+ * vertex set of \p graph.+ * \param quantities A vector of quantities providing the quantity of each+ * vertex in \p graph. Think of each entry of the vector as being+ * generated by a function such as the fitness function for the game.+ * So if the vector represents fitness quantities, then each vector+ * entry is the fitness of some vertex. The length of this vector must+ * be the same as the number of vertices in the vertex set of \p graph.+ * For the purpose of roulette wheel selection, each vector entry is+ * assumed to be nonnegative; no checks will be performed for this. It+ * is your responsibility to ensure that at least one entry is nonzero.+ * Furthermore, this vector cannot be a vector of zeros; this condition+ * will be checked.+ * \param strategies A vector of the current strategies for the vertex+ * population. The updated strategy for \p vid would be stored here.+ * Each strategy is identified with a nonnegative integer, whose+ * interpretation depends on the payoff matrix of the game. Generally+ * we use the strategy ID as a row or column index of the payoff+ * matrix. The length of this vector must be the same as the number of+ * vertices in the vertex set of \p graph.+ * \param mode Defines the sort of neighbourhood to consider for \p vid. This+ * is only relevant if we are considering the local perspective, i.e. if+ * \p islocal is true. If we are considering the global perspective,+ * then it is safe to pass the value \p IGRAPH_ALL here. If \p graph is+ * undirected, then we use all the immediate neighbours of \p vid. Thus+ * if you know that \p graph is undirected, then it is safe to pass the+ * value \p IGRAPH_ALL here. Supported values are:+ * \clist+ * \cli IGRAPH_OUT+ * Use the out-neighbours of \p vid. This option is only relevant+ * when \p graph is a digraph and we are considering the local+ * perspective.+ * \cli IGRAPH_IN+ * Use the in-neighbours of \p vid. Again this option is only relevant+ * when \p graph is a directed graph and we are considering the local+ * perspective.+ * \cli IGRAPH_ALL+ * Use both the in- and out-neighbours of \p vid. This option is only+ * relevant if \p graph is a digraph. Also use this value if+ * \p graph is undirected or we are considering the global+ * perspective.+ * \endclist+ * \return The error code \p IGRAPH_EINVAL is returned in each of the following+ * cases: (1) Any of the parameters \p graph, \p quantities, or+ * \p strategies is a null pointer. (2) The vector \p quantities or+ * \p strategies has a length different from the number of vertices+ * in \p graph. (3) The parameter \p graph is the empty or null graph,+ * i.e. the graph with zero vertices and edges. (4) The vector+ * \p quantities sums to zero.+ *+ * Time complexity: O(n) where n is the number of vertices in the perspective+ * to consider. If we consider the global perspective, then n is the number+ * of vertices in the vertex set of \p graph. On the other hand, for the local+ * perspective n is the degree of \p vid, excluding loops.+ *+ * </para><para>+ * Reference:+ * \clist+ * \cli (Yu & Gen 2010)+ * X. Yu and M. Gen. \emb Introduction to Evolutionary Algorithms. \eme+ * Springer, 2010, pages 18--20.+ * \endclist+ *+ * \example examples/simple/igraph_roulette_wheel_imitation.c+ */++int igraph_roulette_wheel_imitation(const igraph_t *graph,+ igraph_integer_t vid,+ igraph_bool_t islocal,+ const igraph_vector_t *quantities,+ igraph_vector_t *strategies,+ igraph_neimode_t mode) {+ igraph_bool_t updates;+ igraph_integer_t u;+ igraph_real_t r; /* random number */+ igraph_vector_t V; /* vector of cumulative proportionate quantities */+ igraph_vit_t A; /* all vertices in v's perspective */+ igraph_vs_t vs;+ long int i;++ IGRAPH_CHECK(igraph_microscopic_standard_tests(graph, vid, quantities,+ strategies, mode, &updates,+ islocal));+ if (!updates) {+ return IGRAPH_SUCCESS; /* nothing further to do */+ }++ /* set the perspective */+ if (islocal) {+ IGRAPH_CHECK(igraph_vs_adj(&vs, vid, mode));+ } else {+ IGRAPH_CHECK(igraph_vs_all(&vs));+ }+ IGRAPH_FINALLY(igraph_vs_destroy, &vs);+ IGRAPH_CHECK(igraph_vit_create(graph, vs, &A));+ IGRAPH_FINALLY(igraph_vit_destroy, &A);++ IGRAPH_CHECK(igraph_vcumulative_proportionate_values(graph, quantities, &V,+ islocal, vid, mode));++ /* Finally, choose a vertex u to imitate. The vertex u is chosen */+ /* proportionate to its quantity. In the case of a local perspective, we */+ /* pretend that v's cumulative proportionate quantity has been appended to */+ /* the vector V. Let V be of length n so that V[n-1] is the last element */+ /* of V, and let r be a real number chosen uniformly at random from the */+ /* unit interval [0,1]. If r > V[i] for all i < n, then v defaults to */+ /* retaining its current strategy. Similarly in the case of the global */+ /* perspective, if r > V[i] for all i < n - 1 then v would adopt the */+ /* strategy of the vertex whose cumulative proportionate quantity is */+ /* V[n-1]. */+ /* NOTE: Here we assume that the order in which we iterate through the */+ /* vertices in A is the same as the order in which we do so in the */+ /* invoked function igraph_vcumulative_proportionate_values(). */+ /* Otherwise we would incorrectly associate each V[i] with a vertex in A. */+ RNG_BEGIN();+ r = RNG_UNIF01();+ RNG_END();+ i = 0;+ while (!IGRAPH_VIT_END(A)) {+ if (r <= VECTOR(V)[i]) {+ /* We have found our candidate vertex for imitation. Update strategy */+ /* of v to that of u, and exit the selection loop. */+ u = (igraph_integer_t)IGRAPH_VIT_GET(A);+ VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];+ break;+ }+ i++;+ IGRAPH_VIT_NEXT(A);+ }++ /* By now, vertex v should either retain its current strategy or it has */+ /* adopted the strategy of a vertex in its perspective. Nothing else to */+ /* do, but clean up. */+ igraph_vector_destroy(&V);+ igraph_vit_destroy(&A);+ igraph_vs_destroy(&vs);+ IGRAPH_FINALLY_CLEAN(3);++ return IGRAPH_SUCCESS;+}++/**+ * \ingroup spatialgames+ * \function igraph_stochastic_imitation+ * \brief Adopt a strategy via stochastic imitation with uniform selection.+ *+ * A simple stochastic imitation strategy where a vertex revises its+ * strategy to that of a vertex chosen uniformly at random from its local+ * neighbourhood. This is called stochastic imitation via uniform selection,+ * where the strategy to imitate is chosen via some random process. For the+ * purposes of this function, we use uniform selection from a pool of+ * candidates.+ *+ * \param graph The graph object representing the game network. This cannot+ * be the empty or trivial graph, but must have at least two vertices+ * and one edge. If \p graph has one vertex, then no strategy update+ * would take place. Furthermore, if \p graph has at least two vertices+ * but zero edges, then strategy update would also not take place.+ * \param vid The vertex whose strategy is to be updated. It is assumed that+ * \p vid represents a vertex in \p graph. No checking is performed and+ * it is your responsibility to ensure that \p vid is indeed a vertex+ * of \p graph. If an isolated vertex is provided, i.e. the input+ * vertex has degree 0, then no strategy update would take place and+ * \p vid would retain its current strategy. Strategy update would also+ * not take place if the local neighbourhood of \p vid are its+ * in-neighbours (respectively out-neighbours), but \p vid has zero+ * in-neighbours (respectively out-neighbours). Loops are ignored in+ * computing the degree (in, out, all) of \p vid.+ * \param algo This flag controls which algorithm to use in stochastic+ * imitation. Supported values are:+ * \clist+ * \cli IGRAPH_IMITATE_AUGMENTED+ * Augmented imitation. Vertex \p vid imitates the strategy of the+ * chosen vertex u provided that doing so would increase the+ * quantity (e.g. fitness) of \p vid. Augmented imitation can be+ * thought of as "imitate if better".+ * \cli IGRAPH_IMITATE_BLIND+ * Blind imitation. Vertex \p vid blindly imitates the strategy of+ * the chosen vertex u, regardless of whether doing so would+ * increase or decrease the quantity of \p vid.+ * \cli IGRAPH_IMITATE_CONTRACTED+ * Contracted imitation. Here vertex \p vid imitates the strategy of+ * the chosen vertex u if doing so would decrease the quantity of+ * \p vid. Think of contracted imitation as "imitate if worse".+ * \endclist+ * \param quantities A vector of quantities providing the quantity of each+ * vertex in \p graph. Think of each entry of the vector as being+ * generated by a function such as the fitness function for the game.+ * So if the vector represents fitness quantities, then each vector+ * entry is the fitness of some vertex. The length of this vector must+ * be the same as the number of vertices in the vertex set of \p graph.+ * \param strategies A vector of the current strategies for the vertex+ * population. The updated strategy for \p vid would be stored here.+ * Each strategy is identified with a nonnegative integer, whose+ * interpretation depends on the payoff matrix of the game. Generally+ * we use the strategy ID as a row or column index of the payoff+ * matrix. The length of this vector must be the same as the number of+ * vertices in the vertex set of \p graph.+ * \param mode Defines the sort of neighbourhood to consider for \p vid. If+ * \p graph is undirected, then we use all the immediate neighbours of+ * \p vid. Thus if you know that \p graph is undirected, then it is safe+ * to pass the value \p IGRAPH_ALL here. Supported values are:+ * \clist+ * \cli IGRAPH_OUT+ * Use the out-neighbours of \p vid. This option is only relevant+ * when \p graph is a directed graph.+ * \cli IGRAPH_IN+ * Use the in-neighbours of \p vid. Again this option is only relevant+ * when \p graph is a directed graph.+ * \cli IGRAPH_ALL+ * Use both the in- and out-neighbours of \p vid. This option is only+ * relevant if \p graph is a digraph. Also use this value if+ * \p graph is undirected.+ * \endclist+ * \return The error code \p IGRAPH_EINVAL is returned in each of the following+ * cases: (1) Any of the parameters \p graph, \p quantities, or+ * \p strategies is a null pointer. (2) The vector \p quantities or+ * \p strategies has a length different from the number of vertices+ * in \p graph. (3) The parameter \p graph is the empty or null graph,+ * i.e. the graph with zero vertices and edges. (4) The parameter+ * \p algo refers to an unsupported stochastic imitation algorithm.+ *+ * Time complexity: depends on the uniform random number generator, but should+ * usually be O(1).+ *+ * \example examples/simple/igraph_stochastic_imitation.c+ */++int igraph_stochastic_imitation(const igraph_t *graph,+ igraph_integer_t vid,+ igraph_imitate_algorithm_t algo,+ const igraph_vector_t *quantities,+ igraph_vector_t *strategies,+ igraph_neimode_t mode) {+ igraph_bool_t updates;+ igraph_integer_t u;+ igraph_vector_t adj;+ int i;++ /* sanity checks */+ if (algo != IGRAPH_IMITATE_AUGMENTED &&+ algo != IGRAPH_IMITATE_BLIND &&+ algo != IGRAPH_IMITATE_CONTRACTED) {+ IGRAPH_ERROR("Unsupported stochastic imitation algorithm",+ IGRAPH_EINVAL);+ }+ IGRAPH_CHECK(igraph_microscopic_standard_tests(graph, vid, quantities,+ strategies, mode, &updates,+ /*is local?*/ 1));+ if (!updates) {+ return IGRAPH_SUCCESS; /* nothing more to do */+ }++ /* immediate neighbours of v */+ IGRAPH_VECTOR_INIT_FINALLY(&adj, 0);+ IGRAPH_CHECK(igraph_neighbors(graph, &adj, vid, mode));++ /* Blind imitation. Let v be the vertex whose strategy we want to revise. */+ /* Choose a vertex u uniformly at random from the immediate neighbours of */+ /* v, including v itself. Then blindly update the strategy of v to that of */+ /* u, irrespective of whether doing so would increase or decrease the */+ /* quantity (e.g. fitness) of v. Here v retains its current strategy if */+ /* the chosen vertex u is indeed v itself. */+ if (algo == IGRAPH_IMITATE_BLIND) {+ IGRAPH_CHECK(igraph_vector_push_back(&adj, vid));+ RNG_BEGIN();+ i = (int) RNG_INTEGER(0, igraph_vector_size(&adj) - 1);+ RNG_END();+ u = (igraph_integer_t) VECTOR(adj)[i];+ VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];+ }+ /* Augmented imitation. Let v be the vertex whose strategy we want to */+ /* revise. Let f be the quantity function for the game. Choose a vertex u */+ /* uniformly at random from the immediate neighbours of v; do not include */+ /* v. Then v imitates the strategy of u if f(u) > f(v). Otherwise v */+ /* retains its current strategy. */+ else if (algo == IGRAPH_IMITATE_AUGMENTED) {+ RNG_BEGIN();+ i = (int) RNG_INTEGER(0, igraph_vector_size(&adj) - 1);+ RNG_END();+ u = (igraph_integer_t) VECTOR(adj)[i];+ if (VECTOR(*quantities)[u] > VECTOR(*quantities)[vid]) {+ VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];+ }+ }+ /* Contracted imitation. Let v be the vertex whose strategy we want to */+ /* update and let f be the quantity function for the game. Choose a vertex */+ /* u uniformly at random from the immediate neighbours of v, excluding v */+ /* itself. Then v imitates the strategy of u provided that f(u) < f(v). */+ /* Otherwise v retains its current strategy. */+ else if (algo == IGRAPH_IMITATE_CONTRACTED) {+ RNG_BEGIN();+ i = (int) RNG_INTEGER(0, igraph_vector_size(&adj) - 1);+ RNG_END();+ u = (igraph_integer_t) VECTOR(adj)[i];+ if (VECTOR(*quantities)[u] < VECTOR(*quantities)[vid]) {+ VECTOR(*strategies)[vid] = VECTOR(*strategies)[u];+ }+ }++ /* clean up */+ igraph_vector_destroy(&adj);+ IGRAPH_FINALLY_CLEAN(1);++ return IGRAPH_SUCCESS;+}
+ 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(°ree, 0);+ igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL, /*loops=*/ 1);+ igraph_vector_add_constant(°ree, -1);+ igraph_assortativity(graph, °ree, 0, res, /*directed=*/ 0);+ igraph_vector_destroy(°ree);+ }++ 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<->B, C, a graph with a mutual connection between two vertices.+ * \cli 021D+ * A<-B->C, the binary out-tree.+ * \cli 021U+ * A->B<-C, the binary in-tree.+ * \cli 021C+ * A->B->C, the directed line.+ * \cli 111D+ * A<->B<-C.+ * \cli 111U+ * A<->B->C.+ * \cli 030T+ * A->B<-C, A->C.+ * \cli 030C+ * A<-B<-C, A->C.+ * \cli 201+ * A<->B<->C.+ * \cli 120D+ * A<-B->C, A<->C.+ * \cli 120U+ * A->B<-C, A<->C.+ * \cli 120C+ * A->B->C, A<->C.+ * \cli 210+ * A->B<->C, A<->C.+ * \cli 300+ * A<->B<->C, A<->C, the complete graph.+ * \endclist+ *+ * </para><para>+ * See also Davis, J.A. and Leinhardt, S. (1972). The Structure of+ * Positive Interpersonal Relations in Small Groups. In J. Berger+ * (Ed.), Sociological Theories in Progress, Volume 2, 218-251.+ * Boston: Houghton Mifflin.+ *+ * </para><para>+ * This function calls \ref igraph_motifs_randesu() which is an+ * implementation of the FANMOD motif finder tool, see \ref+ * igraph_motifs_randesu() for details. Note that the order of the+ * triads is not the same for \ref igraph_triad_census() and \ref+ * igraph_motifs_randesu().+ *+ * \param graph The input graph. A warning is given for undirected+ * graphs, as the result is undefined for those.+ * \param res Pointer to an initialized vector, the result is stored+ * here in the same order as given in the list above. Note that this+ * order is different than the one used by \ref igraph_motifs_randesu().+ * \return Error code.+ *+ * \sa \ref igraph_motifs_randesu(), \ref igraph_dyad_census().+ *+ * Time complexity: TODO.+ */++int igraph_triad_census(const igraph_t *graph, igraph_vector_t *res) {++ igraph_vector_t cut_prob;+ igraph_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(¶m);+ 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, ¶m);++ 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 > \c h. (2) Assuming that+ * \c l < \c h and N is the sample size, the above error code is+ * returned if N > |\c h - \c l|, i.e. the sample size exceeds the+ * size of the candidate pool.+ *+ * Time complexity: according to (Vitter 1987), the expected+ * running time is O(length).+ *+ * </para><para>+ * Reference:+ * \clist+ * \cli (Vitter 1987)+ * J. S. Vitter. An efficient algorithm for sequential random sampling.+ * \emb ACM Transactions on Mathematical Software, \eme 13(1):58--67, 1987.+ * \endclist+ *+ * \example examples/simple/igraph_random_sample.c+ */++int igraph_random_sample(igraph_vector_t *res, igraph_real_t l, igraph_real_t h,+ igraph_integer_t length) {+ igraph_real_t N = h - l + 1;+ igraph_real_t n = length;+ int retval;++ igraph_real_t nreal = length;+ igraph_real_t ninv = (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., & 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 = °ree; /* reuse degree as edge1 */++ if (igraph_vector_size(weights) != igraph_ecount(graph)) {+ IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL);+ }++ igraph_vector_int_init(&order, no_of_nodes);+ IGRAPH_FINALLY(igraph_vector_int_destroy, &order);+ IGRAPH_VECTOR_INIT_FINALLY(°ree, no_of_nodes);++ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL,+ IGRAPH_LOOPS));+ maxdegree = (long int) igraph_vector_max(°ree) + 1;+ igraph_vector_order1_int(°ree, &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(°ree);+ 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' < n and L, R are from C[n'xn]} and are such+ * that LR*=I[n'] (R* denotes the conjugate transpose of R). Under+ * these assumptions, it can be shown that P=R*L is an n'-rank+ * projector and that, if (lambda, v) is a (right)+ * eigenpair of M (i.e. Mv=lambda v} and P is orthogonal, there exists+ * an eigenvalue lambda' of M' such that+ * <blockquote><para><phrase role="math">+ * |lambda-lambda'| <= const ||e[P](v)||+ * [1+O(||e[P](v)||<superscript>2</superscript>)],+ * </phrase></para></blockquote>+ * where ||e[P](v)||=||v-Pv||. Hence, if P (or equivalently+ * L, R) is chosen so as to make ||e[P](v)|| as small as possible, one+ * can preserve to any desired level the original eigenvalue+ * lambda in the coarse-grained matrix M';+ * under extra assumptions on M, this result can be generalized to+ * eigenvectors [1]. This leads to the following generic definition of a+ * SCG problem.+ * </para>+ *+ * <para>+ * Given M (C[nxn]) and (lambda, v), a (right) eigenpair of M to be+ * preserved by the coarse graining, the problem is to find a projector+ * P' solving+ * <blockquote><para><phrase role="math">+ * min(||e[P](v)||, p in Omega),+ * </phrase></para></blockquote>+ * where Omega is a set of projectors in C[nxn] described by some+ * ad hoc constraints c[1], ..., c[r]+ * (e.g. c[1]: P in R[nxn], c[2]: P=t(P), c[3]: P[i,j] >= 0}, etc).+ * </para>+ *+ * <para>+ * Choosing pertinent constraints to solve the SCG problem is of great+ * importance in applications. For instance, in the absence of+ * constraints the SCG problem is solved trivially by+ * P'=vv* (v is assumed normalized). We have designed a particular+ * constraint, called <emphasis>homogeneous mixing</emphasis>, which+ * ensures that vertices belonging to the same group are merged+ * consistently from a physical point of view (see [1] for+ * details). Under this constraint the SCG problem reduces to finding+ * the partition of 1, ..., n (labeling the original vertices)+ * minimizing+ * <blockquote><para><phrase role="math">+ * ||e[P](v)||<superscript>2</superscript> =+ * sum([v(i)-(Pv)(i)]<superscript>2</superscript>;+ * alpha=1,...,n', i in alpha),+ * </phrase></para></blockquote>+ * where alpha denotes a group (i.e. a block) in a partition of+ * {1, ..., n}, and |alpha| is the number of elements in alpha.+ * </para>+ *+ * <para>+ * If M is symmetric or stochastic, for instance, then it may be+ * desirable (or mandatory) to choose L, R so that M' is symmetric or+ * stochastic as well. This <emphasis>structural constraint</emphasis>+ * has led to the construction of particular semi-projectors for+ * symmetric [1], stochastic [3] and Laplacian [2] matrices, that are+ * made available.+ * </para>+ *+ * <para>+ * In short, the coarse graining of matrices and graphs involves:+ * \olist+ * \oli Retrieving a matrix or a graph matrix M from the+ * problem.+ * \oli Computing the eigenpairs of M to be preserved in the+ * coarse-grained graph or matrix.+ * \oli Setting some problem-specific constraints (e.g. dimension of+ * the coarse-grained object).+ * \oli Solving the constrained SCG problem, that is finding P'.+ * \oli Computing from P' two semi-projectors L' and R'+ * (e.g. following the method proposed in [1]).+ * \oli Working out the product M'=L'MR'* and, if needed, defining+ * from M' a coarse-grained graph.+ * \endolist+ * </para>+ * </section>+ *+ * <section><title>Functions for performing SCG</title>+ * <para>+ * The main functions are \ref igraph_scg_adjacency(), \ref+ * igraph_scg_laplacian() and \ref igraph_scg_stochastic().+ * These functions handle all the steps involved in the+ * Spectral Coarse Graining (SCG) of some particular matrices and graphs+ * as described above and in reference [1]. In more details,+ * they compute some prescribed eigenpairs of a matrix or a+ * graph matrix, (for now adjacency, Laplacian and stochastic matrices are+ * available), work out an optimal partition to preserve the eigenpairs,+ * and finally output a coarse-grained matrix or graph along with other+ * useful information.+ * </para>+ *+ * <para>+ * These steps can also be carried out independently: (1) Use+ * \ref igraph_get_adjacency(), \ref igraph_get_sparsemat(),+ * \ref igraph_laplacian(), \ref igraph_get_stochastic() or \ref+ * igraph_get_stochastic_sparsemat() to compute a matrix M.+ * (2) Work out some prescribed eigenpairs of M e.g. by+ * means of \ref igraph_arpack_rssolve() or \ref+ * igraph_arpack_rnsolve(). (3) Invoke one the four+ * algorithms of the function \ref igraph_scg_grouping() to get a+ * partition that will preserve the eigenpairs in the coarse-grained+ * matrix. (4) Compute the semi-projectors L and R using+ * \ref igraph_scg_semiprojectors() and from there the coarse-grained+ * matrix M'=LMR*. If necessary, construct a coarse-grained graph from+ * M' (e.g. as in [1]).+ * </para>+ * </section>+ *+ * <section><title>References</title>+ * <para>+ * [1] D. Morton de Lachapelle, D. Gfeller, and P. De Los Rios,+ * Shrinking Matrices while Preserving their Eigenpairs with Application+ * to the Spectral Coarse Graining of Graphs. Submitted to+ * <emphasis>SIAM Journal on Matrix Analysis and+ * Applications</emphasis>, 2008.+ * http://people.epfl.ch/david.morton+ * </para>+ * <para>+ * [2] D. Gfeller, and P. De Los Rios, Spectral Coarse Graining and+ * Synchronization in Oscillator Networks.+ * <emphasis>Physical Review Letters</emphasis>,+ * <emphasis role="strong">100</emphasis>(17), 2008.+ * http://arxiv.org/abs/0708.2055+ * </para>+ * <para>+ * [3] D. Gfeller, and P. De Los Rios, Spectral Coarse Graining of Complex+ * Networks, <emphasis>Physical Review Letters</emphasis>,+ * <emphasis role="strong">99</emphasis>(3), 2007.+ * http://arxiv.org/abs/0706.0812+ * </para>+ * </section>+ */++/**+ * \function igraph_scg_grouping+ * \brief SCG problem solver+ *+ * This function solves the Spectral Coarse Graining (SCG) problem;+ * either exactly, or approximately but faster.+ *+ * </para><para>+ * The algorithm \c IGRAPH_SCG_OPTIMUM solves exactly the SCG problem+ * for each eigenvector in \p V. The running time of this algorithm is+ * O(max(nt) m^2) for the symmetric and laplacian matrix problems+ * It is O(m^3) for the stochastic problem. Here m is the number+ * of rows in \p V. In all three cases, the memory usage is O(m^2).+ *+ * </para><para>+ * The algorithms \c IGRAPH_SCG_INTERV and \c IGRAPH_SCG_INTERV_KM solve+ * approximately the SCG problem by performing a (for now) constant+ * binning of the components of the eigenvectors, that is \p nt+ * <code>VECTOR(nt_vec)[i]</code>) constant-size bins are used to+ * partition <code>V[,i]</code>. When \p algo is \c+ * IGRAPH_SCG_INTERV_KM, the (Lloyd) k-means algorithm is+ * run on each partition obtained by \c IGRAPH_SCG_INTERV to improve+ * accuracy.+ *+ * </para><para>+ * Once a minimizing partition (either exact or approximate) has been+ * found for each eigenvector, the final grouping is worked out as+ * follows: two vertices are grouped together in the final partition if+ * they are grouped together in each minimizing partition. In general the+ * size of the final partition is not known in advance when the number+ * of columns in \p V is larger than one.+ *+ * </para><para>+ * Finally, the algorithm \c IGRAPH_SCG_EXACT groups the vertices with+ * equal components in each eigenvector. The last three algorithms+ * essentially have linear running time and memory load.+ *+ * \param V The matrix of eigenvectors to be preserved by coarse+ * graining, each column is an eigenvector.+ * \param groups Pointer to an initialized vector, the result of the+ * SCG is stored here.+ * \param nt Positive integer. When \p algo is \c IGRAPH_SCG_OPTIMUM,+ * it gives the number of groups to partition each eigenvector+ * separately. When \p algo is \c IGRAPH_SCG_INTERV or \c+ * IGRAPH_SCG_INTERV_KM, it gives the number of intervals to+ * partition each eigenvector. This is ignored when \p algo is \c+ * IGRAPH_SCG_EXACT.+ * \param nt_vec A numeric vector of length one or the length must+ * match the number of eigenvectors given in \p V, or a \c NULL+ * pointer. If not \c NULL, then this argument gives the number of+ * groups or intervals, and \p nt is ignored. Different number of+ * groups or intervals can be specified for each eigenvector.+ * \param mtype The type of semi-projectors used in the SCG. Possible+ * values are \c IGRAPH_SCG_SYMMETRIC, \c IGRAPH_SCG_STOCHASTIC and+ * \c IGRAPH_SCG_LAPLACIAN.+ * \param algo The algorithm to solve the SCG problem. Possible+ * values: \c IGRAPH_SCG_OPTIMUM, \c IGRAPH_SCG_INTERV_KM, \c+ * IGRAPH_SCG_INTERV and \c IGRAPH_SCG_EXACT. Please see the+ * details about them above.+ * \param p A probability vector, or \c NULL. This argument must be+ * given if \p mtype is \c IGRAPH_SCG_STOCHASTIC, but it is ignored+ * otherwise. For the stochastic case it gives the stationary+ * probability distribution of a Markov chain, the one specified by+ * the graph/matrix under study.+ * \param maxiter A positive integer giving the number of iterations+ * of the k-means algorithm when \p algo is \c+ * IGRAPH_SCG_INTERV_KM. It is ignored in other cases. A reasonable+ * (initial) value for this argument is 100.+ * \return Error code.+ *+ * Time complexity: see description above.+ *+ * \sa \ref igraph_scg_adjacency(), \ref igraph_scg_laplacian(), \ref+ * igraph_scg_stochastic().+ *+ * \example examples/simple/igraph_scg_grouping.c+ * \example examples/simple/igraph_scg_grouping2.c+ * \example examples/simple/igraph_scg_grouping3.c+ * \example examples/simple/igraph_scg_grouping4.c+ */++int igraph_scg_grouping(const igraph_matrix_t *V,+ igraph_vector_t *groups,+ igraph_integer_t nt,+ const igraph_vector_t *nt_vec,+ igraph_scg_matrix_t mtype,+ igraph_scg_algorithm_t algo,+ const igraph_vector_t *p,+ igraph_integer_t maxiter) {++ int no_of_nodes = (int) igraph_matrix_nrow(V);+ int nev = (int) igraph_matrix_ncol(V);+ igraph_matrix_int_t gr_mat;+ int i;++ if (nt_vec && igraph_vector_size(nt_vec) != 1 &&+ igraph_vector_size(nt_vec) != nev) {+ IGRAPH_ERROR("Invalid length for interval specification", IGRAPH_EINVAL);+ }+ if (nt_vec && igraph_vector_size(nt_vec) == 1) {+ nt = (igraph_integer_t) VECTOR(*nt_vec)[0];+ nt_vec = 0;+ }++ if (!nt_vec && algo != IGRAPH_SCG_EXACT) {+ if (nt <= 1 || nt >= no_of_nodes) {+ IGRAPH_ERROR("Invalid interval specification", IGRAPH_EINVAL);+ }+ } else if (algo != IGRAPH_SCG_EXACT) {+ igraph_real_t min, max;+ igraph_vector_minmax(nt_vec, &min, &max);+ if (min <= 1 || max >= no_of_nodes) {+ IGRAPH_ERROR("Invalid interval specification", IGRAPH_EINVAL);+ }+ }++ if (mtype == IGRAPH_SCG_STOCHASTIC && !p) {+ IGRAPH_ERROR("`p' must be given for the stochastic matrix case",+ IGRAPH_EINVAL);+ }++ if (p && igraph_vector_size(p) != no_of_nodes) {+ IGRAPH_ERROR("Invalid `p' vector size", IGRAPH_EINVAL);+ }++ IGRAPH_CHECK(igraph_vector_resize(groups, no_of_nodes));++#define INVEC(i) (nt_vec ? VECTOR(*nt_vec)[i] : nt)++ IGRAPH_CHECK(igraph_matrix_int_init(&gr_mat, no_of_nodes, nev));+ IGRAPH_FINALLY(igraph_matrix_int_destroy, &gr_mat);++ switch (algo) {+ case IGRAPH_SCG_OPTIMUM:+ for (i = 0; i < nev; i++) {+ IGRAPH_CHECK(igraph_i_optimal_partition(&MATRIX(*V, 0, i),+ &MATRIX(gr_mat, 0, i),+ no_of_nodes, (int) INVEC(i),+ mtype,+ p ? VECTOR(*p) : 0, 0));+ }+ break;+ case IGRAPH_SCG_INTERV_KM:+ for (i = 0; i < nev; i++) {+ igraph_vector_t tmpv;+ igraph_vector_view(&tmpv, &MATRIX(*V, 0, i), no_of_nodes);+ IGRAPH_CHECK(igraph_i_intervals_plus_kmeans(&tmpv,+ &MATRIX(gr_mat, 0, i),+ no_of_nodes, (int) INVEC(i),+ maxiter));+ }+ break;+ case IGRAPH_SCG_INTERV:+ for (i = 0; i < nev; i++) {+ igraph_vector_t tmpv;+ igraph_vector_view(&tmpv, &MATRIX(*V, 0, i), no_of_nodes);+ IGRAPH_CHECK(igraph_i_intervals_method(&tmpv,+ &MATRIX(gr_mat, 0, i),+ no_of_nodes, (int) INVEC(i)));+ }+ break;+ case IGRAPH_SCG_EXACT:+ for (i = 0; i < nev; i++) {+ IGRAPH_CHECK(igraph_i_exact_coarse_graining(&MATRIX(*V, 0, i),+ &MATRIX(gr_mat, 0, i),+ no_of_nodes));+ }+ break;+ }++#undef INVEC++ if (nev == 1) {+ for (i = 0; i < no_of_nodes; i++) {+ VECTOR(*groups)[i] = MATRIX(gr_mat, i, 0);+ }+ } else {+ igraph_i_scg_groups_t *g = igraph_Calloc(no_of_nodes,+ igraph_i_scg_groups_t);+ int gr_nb = 0;++ IGRAPH_CHECK(igraph_matrix_int_transpose(&gr_mat));+ for (i = 0; i < no_of_nodes; i++) {+ g[i].ind = i;+ g[i].n = nev;+ g[i].gr = &MATRIX(gr_mat, 0, i);+ }++ qsort(g, (size_t) no_of_nodes, sizeof(igraph_i_scg_groups_t),+ igraph_i_compare_groups);+ VECTOR(*groups)[g[0].ind] = gr_nb;+ for (i = 1; i < no_of_nodes; i++) {+ if (igraph_i_compare_groups(&g[i], &g[i - 1]) != 0) {+ gr_nb++;+ }+ VECTOR(*groups)[g[i].ind] = gr_nb;+ }+ igraph_Free(g);+ }++ igraph_matrix_int_destroy(&gr_mat);+ IGRAPH_FINALLY_CLEAN(1);++ return 0;+}++int igraph_i_scg_semiprojectors_sym(const igraph_vector_t *groups,+ igraph_matrix_t *L,+ igraph_matrix_t *R,+ igraph_sparsemat_t *Lsparse,+ igraph_sparsemat_t *Rsparse,+ int no_of_groups,+ int no_of_nodes) {++ igraph_vector_t tab;+ int i;++ IGRAPH_VECTOR_INIT_FINALLY(&tab, no_of_groups);+ for (i = 0; i < no_of_nodes; i++) {+ VECTOR(tab)[ (int) VECTOR(*groups)[i] ] += 1;+ }+ for (i = 0; i < no_of_groups; i++) {+ VECTOR(tab)[i] = sqrt(VECTOR(tab)[i]);+ }++ if (L) {+ IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));+ igraph_matrix_null(L);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*L, g, i) = 1 / VECTOR(tab)[g];+ }+ }++ if (R) {+ if (L) {+ IGRAPH_CHECK(igraph_matrix_update(R, L));+ } else {+ IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));+ igraph_matrix_null(R);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*R, g, i) = 1 / VECTOR(tab)[g];+ }+ }+ }++ if (Lsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i, 1 / VECTOR(tab)[g]));+ }+ }++ if (Rsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i, 1 / VECTOR(tab)[g]));+ }+ }++ igraph_vector_destroy(&tab);+ IGRAPH_FINALLY_CLEAN(1);++ return 0;+}++int igraph_i_scg_semiprojectors_lap(const igraph_vector_t *groups,+ igraph_matrix_t *L,+ igraph_matrix_t *R,+ igraph_sparsemat_t *Lsparse,+ igraph_sparsemat_t *Rsparse,+ int no_of_groups,+ int no_of_nodes,+ igraph_scg_norm_t norm) {++ igraph_vector_t tab;+ int i;++ IGRAPH_VECTOR_INIT_FINALLY(&tab, no_of_groups);+ for (i = 0; i < no_of_nodes; i++) {+ VECTOR(tab)[ (int) VECTOR(*groups)[i] ] += 1;+ }+ for (i = 0; i < no_of_groups; i++) {+ VECTOR(tab)[i] = VECTOR(tab)[i];+ }++ if (norm == IGRAPH_SCG_NORM_ROW) {+ if (L) {+ IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));+ igraph_matrix_null(L);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*L, g, i) = 1.0 / VECTOR(tab)[g];+ }+ }+ if (R) {+ IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));+ igraph_matrix_null(R);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*R, g, i) = 1.0;+ }+ }+ if (Lsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i,+ 1.0 / VECTOR(tab)[g]));+ }+ }+ if (Rsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i, 1.0));+ }+ }+ } else {+ if (L) {+ IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));+ igraph_matrix_null(L);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*L, g, i) = 1.0;+ }+ }+ if (R) {+ IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));+ igraph_matrix_null(R);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*R, g, i) = 1.0 / VECTOR(tab)[g];+ }+ }+ if (Lsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i, 1.0));+ }+ }+ if (Rsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i,+ 1.0 / VECTOR(tab)[g]));+ }+ }++ }++ igraph_vector_destroy(&tab);+ IGRAPH_FINALLY_CLEAN(1);++ return 0;+}++int igraph_i_scg_semiprojectors_sto(const igraph_vector_t *groups,+ igraph_matrix_t *L,+ igraph_matrix_t *R,+ igraph_sparsemat_t *Lsparse,+ igraph_sparsemat_t *Rsparse,+ int no_of_groups,+ int no_of_nodes,+ const igraph_vector_t *p,+ igraph_scg_norm_t norm) {++ igraph_vector_t pgr, pnormed;+ int i;++ IGRAPH_VECTOR_INIT_FINALLY(&pgr, no_of_groups);+ IGRAPH_VECTOR_INIT_FINALLY(&pnormed, no_of_nodes);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ VECTOR(pgr)[g] += VECTOR(*p)[i];+ }+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ VECTOR(pnormed)[i] = VECTOR(*p)[i] / VECTOR(pgr)[g];+ }++ if (norm == IGRAPH_SCG_NORM_ROW) {+ if (L) {+ IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));+ igraph_matrix_null(L);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*L, g, i) = VECTOR(pnormed)[i];+ }+ }+ if (R) {+ IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));+ igraph_matrix_null(R);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*R, g, i) = 1.0;+ }+ }+ if (Lsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i,+ VECTOR(pnormed)[i]));+ }+ }+ if (Rsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i, 1.0));+ }+ }+ } else {+ if (L) {+ IGRAPH_CHECK(igraph_matrix_resize(L, no_of_groups, no_of_nodes));+ igraph_matrix_null(L);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int ) VECTOR(*groups)[i];+ MATRIX(*L, g, i) = 1.0;+ }+ }+ if (R) {+ IGRAPH_CHECK(igraph_matrix_resize(R, no_of_groups, no_of_nodes));+ igraph_matrix_null(R);+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ MATRIX(*R, g, i) = VECTOR(pnormed)[i];+ }+ }+ if (Lsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Lsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Lsparse, g, i, 1.0));+ }+ }+ if (Rsparse) {+ IGRAPH_CHECK(igraph_sparsemat_init(Rsparse, no_of_groups, no_of_nodes,+ /* nzmax= */ no_of_nodes));+ for (i = 0; i < no_of_nodes; i++) {+ int g = (int) VECTOR(*groups)[i];+ IGRAPH_CHECK(igraph_sparsemat_entry(Rsparse, g, i,+ VECTOR(pnormed)[i]));+ }+ }+ }+++ igraph_vector_destroy(&pnormed);+ igraph_vector_destroy(&pgr);+ IGRAPH_FINALLY_CLEAN(2);++ return 0;+}++/**+ * \function igraph_scg_semiprojectors+ * \brief Compute SCG semi-projectors for a given partition+ *+ * The three types of semi-projectors are defined as follows.+ * Let gamma(j) label the group of vertex j in a partition of all the+ * vertices.+ *+ * </para><para>+ * The symmetric semi-projectors are defined as+ * <blockquote><para><phrase role="math">+ * L[alpha,j] = R[alpha,j] = 1/sqrt(|alpha|) delta[alpha,gamma(j)],+ * </phrase></para></blockquote>+ * the (row) Laplacian semi-projectors as+ * <blockquote><para><phrase role="math">+ * L[alpha,j] = 1/|alpha| delta[alpha,gamma(j)]+ * </phrase></para></blockquote>+ * and+ * <blockquote><para><phrase role="math">+ * R[alpha,j] = delta[alpha,gamma(j)],+ * </phrase></para></blockquote>+ * and the (row) stochastic semi-projectors as+ * <blockquote><para><phrase role="math">+ * L[alpha,j] = p[1][j] / sum(p[1][k]; k in gamma(j))+ * delta[alpha,gamma(j)]+ * </phrase></para></blockquote>+ * and+ * <blockquote><para><phrase role="math">+ * R[alpha,j] = delta[alpha,gamma(j)],+ * </phrase></para></blockquote>+ * where p[1] is the (left) eigenvector associated with the+ * one-eigenvalue of the stochastic matrix. L and R are+ * defined in a symmetric way when \p norm is \c+ * IGRAPH_SCG_NORM_COL. All these semi-projectors verify various+ * properties described in the reference.+ * \param groups A vector of integers, giving the group label of every+ * vertex in the partition. Group labels should start at zero and+ * should be sequential.+ * \param mtype The type of semi-projectors. For now \c+ * IGRAPH_SCG_SYMMETRIC, \c IGRAPH_SCG_STOCHASTIC and \c+ * IGRAP_SCG_LAPLACIAN are supported.+ * \param L If not a \c NULL pointer, then it must be a pointer to+ * an initialized matrix. The left semi-projector is stored here.+ * \param R If not a \c NULL pointer, then it must be a pointer to+ * an initialized matrix. The right semi-projector is stored here.+ * \param Lsparse If not a \c NULL pointer, then it must be a pointer+ * to an uninitialized sparse matrix. The left semi-projector is+ * stored here.+ * \param Rsparse If not a \c NULL pointer, then it must be a pointer+ * to an uninitialized sparse matrix. The right semi-projector is+ * stored here.+ * \param p \c NULL, or a probability vector of the same length as \p+ * groups. \p p is the stationary probability distribution of a+ * Markov chain when \p mtype is \c IGRAPH_SCG_STOCHASTIC. This+ * argument is ignored in all other cases.+ * \param norm Either \c IGRAPH_SCG_NORM_ROW or \c IGRAPH_SCG_NORM_COL.+ * Specifies whether the rows or the columns of the Laplacian+ * matrix sum up to zero, or whether the rows or the columns of the+ * stochastic matrix sum up to one.+ * \return Error code.+ *+ * Time complexity: TODO.+ *+ * \sa \ref igraph_scg_adjacency(), \ref igraph_scg_stochastic() and+ * \ref igraph_scg_laplacian(), \ref igraph_scg_grouping().+ *+ * \example examples/simple/igraph_scg_semiprojectors.c+ * \example examples/simple/igraph_scg_semiprojectors2.c+ * \example examples/simple/igraph_scg_semiprojectors3.c+ */++int igraph_scg_semiprojectors(const igraph_vector_t *groups,+ igraph_scg_matrix_t mtype,+ igraph_matrix_t *L,+ igraph_matrix_t *R,+ igraph_sparsemat_t *Lsparse,+ igraph_sparsemat_t *Rsparse,+ const igraph_vector_t *p,+ igraph_scg_norm_t norm) {++ int no_of_nodes = (int) igraph_vector_size(groups);+ int no_of_groups;+ igraph_real_t min, max;++ igraph_vector_minmax(groups, &min, &max);+ no_of_groups = (int) max + 1;++ if (min < 0 || max >= no_of_nodes) {+ IGRAPH_ERROR("Invalid membership vector", IGRAPH_EINVAL);+ }++ if (mtype == IGRAPH_SCG_STOCHASTIC && !p) {+ IGRAPH_ERROR("`p' must be given for the stochastic matrix case",+ IGRAPH_EINVAL);+ }++ if (p && igraph_vector_size(p) != no_of_nodes) {+ IGRAPH_ERROR("Invalid `p' vector length, should match number of vertices",+ IGRAPH_EINVAL);+ }++ switch (mtype) {+ case IGRAPH_SCG_SYMMETRIC:+ IGRAPH_CHECK(igraph_i_scg_semiprojectors_sym(groups, L, R, Lsparse,+ Rsparse, no_of_groups,+ no_of_nodes));+ break;++ case IGRAPH_SCG_LAPLACIAN:+ IGRAPH_CHECK(igraph_i_scg_semiprojectors_lap(groups, L, R, Lsparse,+ Rsparse, no_of_groups,+ no_of_nodes, norm));+ break;++ case IGRAPH_SCG_STOCHASTIC:+ IGRAPH_CHECK(igraph_i_scg_semiprojectors_sto(groups, L, R, Lsparse,+ Rsparse, no_of_groups,+ no_of_nodes, p, norm));+ break;+ }++ return 0;+}++/**+ * \function igraph_scg_norm_eps+ * Calculate SCG residuals+ *+ * Computes |v[i]-Pv[i]|, where v[i] is the i-th eigenvector in \p V+ * and P is the projector corresponding to the \p mtype argument.+ *+ * \param V The matrix of eigenvectors to be preserved by coarse+ * graining, each column is an eigenvector.+ * \param groups A vector of integers, giving the group label of every+ * vertex in the partition. Group labels should start at zero and+ * should be sequential.+ * \param eps Pointer to a real value, the result is stored here.+ * \param mtype The type of semi-projectors. For now \c+ * IGRAPH_SCG_SYMMETRIC, \c IGRAPH_SCG_STOCHASTIC and \c+ * IGRAP_SCG_LAPLACIAN are supported.+ * \param p \c NULL, or a probability vector of the same length as \p+ * groups. \p p is the stationary probability distribution of a+ * Markov chain when \p mtype is \c IGRAPH_SCG_STOCHASTIC. This+ * argument is ignored in all other cases.+ * \param norm Either \c IGRAPH_SCG_NORM_ROW or \c IGRAPH_SCG_NORM_COL.+ * Specifies whether the rows or the columns of the Laplacian+ * matrix sum up to zero, or whether the rows or the columns of the+ * stochastic matrix sum up to one.+ * \return Error code.+ *+ * Time complexity: TODO.+ *+ * \sa \ref igraph_scg_adjacency(), \ref igraph_scg_stochastic() and+ * \ref igraph_scg_laplacian(), \ref igraph_scg_grouping(), \ref+ * igraph_scg_semiprojectors().+ */++int igraph_scg_norm_eps(const igraph_matrix_t *V,+ const igraph_vector_t *groups,+ igraph_vector_t *eps,+ igraph_scg_matrix_t mtype,+ const igraph_vector_t *p,+ igraph_scg_norm_t norm) {++ int no_of_nodes = (int) igraph_vector_size(groups);+ int no_of_groups;+ int no_of_vectors = (int) igraph_matrix_ncol(V);+ igraph_real_t min, max;+ igraph_sparsemat_t Lsparse, Rsparse, Lsparse2, Rsparse2, Rsparse3, proj;+ igraph_vector_t x, res;+ int k, i;++ if (igraph_matrix_nrow(V) != no_of_nodes) {+ IGRAPH_ERROR("Eigenvector length and group vector length do not match",+ IGRAPH_EINVAL);+ }++ igraph_vector_minmax(groups, &min, &max);+ no_of_groups = (int) max + 1;++ if (min < 0 || max >= no_of_nodes) {+ IGRAPH_ERROR("Invalid membership vector", IGRAPH_EINVAL);+ }++ if (mtype == IGRAPH_SCG_STOCHASTIC && !p) {+ IGRAPH_ERROR("`p' must be given for the stochastic matrix case",+ IGRAPH_EINVAL);+ }++ if (p && igraph_vector_size(p) != no_of_nodes) {+ IGRAPH_ERROR("Invalid `p' vector length, should match number of vertices",+ IGRAPH_EINVAL);+ }++ IGRAPH_CHECK(igraph_scg_semiprojectors(groups, mtype, /* L= */ 0,+ /* R= */ 0, &Lsparse, &Rsparse, p,+ norm));++ IGRAPH_FINALLY(igraph_sparsemat_destroy, &Lsparse);+ IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse);++ IGRAPH_CHECK(igraph_sparsemat_compress(&Lsparse, &Lsparse2));+ IGRAPH_FINALLY(igraph_sparsemat_destroy, &Lsparse2);+ IGRAPH_CHECK(igraph_sparsemat_compress(&Rsparse, &Rsparse2));+ IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse2);+ IGRAPH_CHECK(igraph_sparsemat_transpose(&Rsparse2, &Rsparse3,+ /*values=*/ 1));+ IGRAPH_FINALLY(igraph_sparsemat_destroy, &Rsparse3);++ IGRAPH_CHECK(igraph_sparsemat_multiply(&Rsparse3, &Lsparse2, &proj));+ IGRAPH_FINALLY(igraph_sparsemat_destroy, &proj);++ IGRAPH_VECTOR_INIT_FINALLY(&res, no_of_nodes);+ IGRAPH_CHECK(igraph_vector_resize(eps, no_of_vectors));++ for (k = 0; k < no_of_vectors; k++) {+ igraph_vector_view(&x, &MATRIX(*V, 0, k), no_of_nodes);+ igraph_vector_null(&res);+ IGRAPH_CHECK(igraph_sparsemat_gaxpy(&proj, &x, &res));+ VECTOR(*eps)[k] = 0.0;+ for (i = 0; i < no_of_nodes; i++) {+ igraph_real_t di = MATRIX(*V, i, k) - VECTOR(res)[i];+ VECTOR(*eps)[k] += di * di;+ }+ VECTOR(*eps)[k] = sqrt(VECTOR(*eps)[k]);+ }++ igraph_vector_destroy(&res);+ igraph_sparsemat_destroy(&proj);+ igraph_sparsemat_destroy(&Rsparse3);+ igraph_sparsemat_destroy(&Rsparse2);+ igraph_sparsemat_destroy(&Lsparse2);+ igraph_sparsemat_destroy(&Rsparse);+ igraph_sparsemat_destroy(&Lsparse);+ IGRAPH_FINALLY_CLEAN(7);++ return 0;+}++int igraph_i_matrix_laplacian(const igraph_matrix_t *matrix,+ igraph_matrix_t *mymatrix,+ igraph_scg_norm_t norm) {++ igraph_vector_t degree;+ int i, j, n = (int) igraph_matrix_nrow(matrix);+ IGRAPH_CHECK(igraph_matrix_resize(mymatrix, n, n));++ IGRAPH_VECTOR_INIT_FINALLY(°ree, n);++ if (norm == IGRAPH_SCG_NORM_ROW) {+ IGRAPH_CHECK(igraph_matrix_rowsum(matrix, °ree));+ } else {+ IGRAPH_CHECK(igraph_matrix_colsum(matrix, °ree));+ }+ 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(°ree);+ 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(°ree, 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(°ree);+ 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(¢ers, n_interv);++ igraph_i_breaks_computation(v, ¢ers, n_interv, 2);+ IGRAPH_CHECK(igraph_i_kmeans_Lloyd(v, n, 1, ¢ers, n_interv, gr,+ maxiter));++ /*renumber the groups*/+ for (i = 0; i < n; i++) {+ gr[i] = gr[i] - 1;+ }++ igraph_vector_destroy(¢ers);+ 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(°, no_of_nodes);+ IGRAPH_VECTOR_INIT_FINALLY(&order, no_of_nodes);+ IGRAPH_CHECK(igraph_degree(graph, °, igraph_vss_all(), IGRAPH_ALL,+ /*loops=*/ 0));++ IGRAPH_CHECK(igraph_vector_order1(°, &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(°);+ 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 = #+ 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(°ree, 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(°ree);+ 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(°ree, no_of_nodes);++ IGRAPH_CHECK(igraph_degree(graph, °ree, 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(°ree);+ 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(°ree, 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, °ree, 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(°ree);+ 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(°rees, 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, °rees, 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(°rees);+ 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(°rees, 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, °rees, 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(°rees);+ 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(°, no_of_nodes);+ IGRAPH_CHECK(igraph_degree(graph, °, 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(°hist, (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(°hist);+ IGRAPH_FINALLY_CLEAN(1);+ }++ igraph_vector_destroy(&neis);+ igraph_vector_destroy(°);+ 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(°, no_of_nodes);+ IGRAPH_CHECK(igraph_degree(graph, °, 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(°hist, (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(°hist);+ IGRAPH_FINALLY_CLEAN(1);+ }++ igraph_vector_destroy(&neis);+ igraph_vector_destroy(°);+ 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(°rees, 0);+ IGRAPH_CHECK(igraph_degree(graph, °rees, vids, mode, loops));+ IGRAPH_CHECK((int) igraph_vector_qsort_ind(°rees, outvids,+ order == IGRAPH_DESCENDING));+ if (only_indices || igraph_vs_is_all(&vids) ) {+ igraph_vector_destroy(°rees);+ 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(°rees);+ 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(°, 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, °, 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(°);+ 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(°ree, 0));+ IGRAPH_FINALLY(igraph_vector_destroy, °ree);++ IGRAPH_CHECK(igraph_degree(graph, °ree, 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(°ree);+ 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<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üfer sequence+ *+ * A Prü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č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üfer sequence+ * \return Error code:+ * \clist+ * \cli IGRAPH_ENOMEM+ * there is not enough memory to perform the operation.+ * \cli IGRAPH_EINVAL+ * invalid Prü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(°ree, 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(°ree);+ 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(°ree, no_of_nodes);++ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL,+ IGRAPH_LOOPS));+ maxdegree = (long int) igraph_vector_max(°ree) + 1;+ igraph_vector_order1(°ree, &order, maxdegree);+ igraph_vector_destroy(°ree);+ 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(°ree, 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(°ree, &order, maxdegree + 1);+ igraph_vector_destroy(°ree);+ 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(°ree, no_of_nodes);++ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL,+ IGRAPH_LOOPS));+ maxdegree = (long int) igraph_vector_max(°ree) + 1;+ igraph_vector_order1(°ree, &order, maxdegree);+ igraph_vector_destroy(°ree);+ 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(°ree, no_of_nodes);++ IGRAPH_CHECK(igraph_degree(graph, °ree, igraph_vss_all(), IGRAPH_ALL,+ IGRAPH_LOOPS));+ maxdegree = (long int) igraph_vector_max(°ree) + 1;+ IGRAPH_CHECK(igraph_vector_order1(°ree, &order, maxdegree));++ IGRAPH_CHECK(igraph_strength(graph, °ree, 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(°ree);+ 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