diff --git a/R/aaa-auto.R b/R/aaa-auto.R index 984ab11885..6ed2b8cdcd 100644 --- a/R/aaa-auto.R +++ b/R/aaa-auto.R @@ -1231,6 +1231,27 @@ feedback_arc_set_impl <- function(graph, weights=NULL, algo=c("approx_eades", "e res } +feedback_vertex_set_impl <- function(graph, weights=NULL, algo=EXACT_IP) { + # Argument checks + ensure_igraph(graph) + if (is.null(weights) && "weight" %in% vertex_attr_names(graph)) { + weights <- V(graph)$weight + } + if (!is.null(weights) && any(!is.na(weights))) { + weights <- as.numeric(weights) + } else { + weights <- NULL + } + + on.exit( .Call(R_igraph_finalizer) ) + # Function call + res <- .Call(R_igraph_feedback_vertex_set, graph, weights, algo) + if (igraph_opt("return.vs.es")) { + res <- create_vs(graph, res) + } + res +} + is_loop_impl <- function(graph, eids=E(graph)) { # Argument checks ensure_igraph(graph) @@ -3511,6 +3532,23 @@ solve_lsap_impl <- function(c, n) { res } +find_cycle_impl <- function(graph, mode) { + # Argument checks + ensure_igraph(graph) + mode <- switch(igraph.match.arg(mode), "out"=1L, "in"=2L, "all"=3L, "total"=3L) + + on.exit( .Call(R_igraph_finalizer) ) + # Function call + res <- .Call(R_igraph_find_cycle, graph, mode) + if (igraph_opt("return.vs.es")) { + res$vertices <- create_vs(graph, res$vertices) + } + if (igraph_opt("return.vs.es")) { + res$edges <- create_es(graph, res$edges) + } + res +} + is_eulerian_impl <- function(graph) { # Argument checks ensure_igraph(graph) diff --git a/src/cpp11.cpp b/src/cpp11.cpp index 40cd73765e..bbd09220f2 100644 --- a/src/cpp11.cpp +++ b/src/cpp11.cpp @@ -163,7 +163,9 @@ extern SEXP R_igraph_extended_chordal_ring(SEXP, SEXP, SEXP); extern SEXP R_igraph_famous(SEXP); extern SEXP R_igraph_farthest_points(SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_feedback_arc_set(SEXP, SEXP, SEXP); +extern SEXP R_igraph_feedback_vertex_set(SEXP, SEXP, SEXP); extern SEXP R_igraph_finalizer(void); +extern SEXP R_igraph_find_cycle(SEXP, SEXP); extern SEXP R_igraph_forest_fire_game(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP R_igraph_from_hrg_dendrogram(SEXP); extern SEXP R_igraph_from_prufer(SEXP); @@ -619,7 +621,9 @@ static const R_CallMethodDef CallEntries[] = { {"R_igraph_famous", (DL_FUNC) &R_igraph_famous, 1}, {"R_igraph_farthest_points", (DL_FUNC) &R_igraph_farthest_points, 4}, {"R_igraph_feedback_arc_set", (DL_FUNC) &R_igraph_feedback_arc_set, 3}, + {"R_igraph_feedback_vertex_set", (DL_FUNC) &R_igraph_feedback_vertex_set, 3}, {"R_igraph_finalizer", (DL_FUNC) &R_igraph_finalizer, 0}, + {"R_igraph_find_cycle", (DL_FUNC) &R_igraph_find_cycle, 2}, {"R_igraph_forest_fire_game", (DL_FUNC) &R_igraph_forest_fire_game, 5}, {"R_igraph_from_hrg_dendrogram", (DL_FUNC) &R_igraph_from_hrg_dendrogram, 1}, {"R_igraph_from_prufer", (DL_FUNC) &R_igraph_from_prufer, 1}, diff --git a/src/rinterface.c b/src/rinterface.c index ba5de8d96e..f45aa23c0c 100644 --- a/src/rinterface.c +++ b/src/rinterface.c @@ -3755,6 +3755,39 @@ SEXP R_igraph_feedback_arc_set(SEXP graph, SEXP weights, SEXP algo) { return(r_result); } +/*-------------------------------------------/ +/ igraph_feedback_vertex_set / +/-------------------------------------------*/ +SEXP R_igraph_feedback_vertex_set(SEXP graph, SEXP weights, SEXP algo) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_int_t c_result; + igraph_vector_t c_weights; + igraph_fvs_algorithm_t c_algo; + SEXP result; + + SEXP r_result; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + if (0 != igraph_vector_int_init(&c_result, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_result); + if (!Rf_isNull(weights)) { R_SEXP_to_vector(weights, &c_weights); } + c_algo = (igraph_fvs_algorithm_t) Rf_asInteger(algo); + /* Call igraph */ + IGRAPH_R_CHECK(igraph_feedback_vertex_set(&c_graph, &c_result, (Rf_isNull(weights) ? 0 : &c_weights), c_algo)); + + /* Convert output */ + PROTECT(result=R_igraph_vector_int_to_SEXPp1(&c_result)); + igraph_vector_int_destroy(&c_result); + IGRAPH_FINALLY_CLEAN(1); + r_result = result; + + UNPROTECT(1); + return(r_result); +} + /*-------------------------------------------/ / igraph_is_loop / /-------------------------------------------*/ @@ -8638,9 +8671,11 @@ SEXP R_igraph_motifs_randesu(SEXP graph, SEXP size, SEXP cut_prob) { IGRAPH_FINALLY(igraph_vector_destroy, &c_hist); IGRAPH_R_CHECK_INT(size); c_size = (igraph_integer_t) REAL(size)[0]; - R_SEXP_to_vector(cut_prob, &c_cut_prob); + if (!Rf_isNull(cut_prob)) { + R_SEXP_to_vector(cut_prob, &c_cut_prob); + } /* Call igraph */ - IGRAPH_R_CHECK(igraph_motifs_randesu(&c_graph, &c_hist, c_size, &c_cut_prob)); + IGRAPH_R_CHECK(igraph_motifs_randesu(&c_graph, &c_hist, c_size, (Rf_isNull(cut_prob) ? 0 : &c_cut_prob))); /* Convert output */ PROTECT(hist=R_igraph_vector_to_SEXP(&c_hist)); @@ -8671,7 +8706,9 @@ SEXP R_igraph_motifs_randesu_estimate(SEXP graph, SEXP size, SEXP cut_prob, SEXP c_est=0; IGRAPH_R_CHECK_INT(size); c_size = (igraph_integer_t) REAL(size)[0]; - R_SEXP_to_vector(cut_prob, &c_cut_prob); + if (!Rf_isNull(cut_prob)) { + R_SEXP_to_vector(cut_prob, &c_cut_prob); + } IGRAPH_R_CHECK_INT(sample_size); c_sample_size = (igraph_integer_t) REAL(sample_size)[0]; if (!Rf_isNull(sample)) { @@ -8682,7 +8719,7 @@ SEXP R_igraph_motifs_randesu_estimate(SEXP graph, SEXP size, SEXP cut_prob, SEXP IGRAPH_FINALLY(igraph_vector_int_destroy, &c_sample); } /* Call igraph */ - IGRAPH_R_CHECK(igraph_motifs_randesu_estimate(&c_graph, &c_est, c_size, &c_cut_prob, c_sample_size, (Rf_isNull(sample) ? 0 : &c_sample))); + IGRAPH_R_CHECK(igraph_motifs_randesu_estimate(&c_graph, &c_est, c_size, (Rf_isNull(cut_prob) ? 0 : &c_cut_prob), c_sample_size, (Rf_isNull(sample) ? 0 : &c_sample))); /* Convert output */ PROTECT(est=NEW_NUMERIC(1)); @@ -8712,9 +8749,11 @@ SEXP R_igraph_motifs_randesu_no(SEXP graph, SEXP size, SEXP cut_prob) { c_no=0; IGRAPH_R_CHECK_INT(size); c_size = (igraph_integer_t) REAL(size)[0]; - R_SEXP_to_vector(cut_prob, &c_cut_prob); + if (!Rf_isNull(cut_prob)) { + R_SEXP_to_vector(cut_prob, &c_cut_prob); + } /* Call igraph */ - IGRAPH_R_CHECK(igraph_motifs_randesu_no(&c_graph, &c_no, c_size, &c_cut_prob)); + IGRAPH_R_CHECK(igraph_motifs_randesu_no(&c_graph, &c_no, c_size, (Rf_isNull(cut_prob) ? 0 : &c_cut_prob))); /* Convert output */ PROTECT(no=NEW_NUMERIC(1)); @@ -11118,6 +11157,53 @@ SEXP R_igraph_solve_lsap(SEXP c, SEXP n) { return(r_result); } +/*-------------------------------------------/ +/ igraph_find_cycle / +/-------------------------------------------*/ +SEXP R_igraph_find_cycle(SEXP graph, SEXP mode) { + /* Declarations */ + igraph_t c_graph; + igraph_vector_int_t c_vertices; + igraph_vector_int_t c_edges; + igraph_neimode_t c_mode; + SEXP vertices; + SEXP edges; + + SEXP r_result, r_names; + /* Convert input */ + R_SEXP_to_igraph(graph, &c_graph); + if (0 != igraph_vector_int_init(&c_vertices, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_vertices); + if (0 != igraph_vector_int_init(&c_edges, 0)) { + igraph_error("", __FILE__, __LINE__, IGRAPH_ENOMEM); + } + IGRAPH_FINALLY(igraph_vector_int_destroy, &c_edges); + c_mode = (igraph_neimode_t) Rf_asInteger(mode); + /* Call igraph */ + IGRAPH_R_CHECK(igraph_find_cycle(&c_graph, &c_vertices, &c_edges, c_mode)); + + /* Convert output */ + PROTECT(r_result=NEW_LIST(2)); + PROTECT(r_names=NEW_CHARACTER(2)); + PROTECT(vertices=R_igraph_vector_int_to_SEXPp1(&c_vertices)); + igraph_vector_int_destroy(&c_vertices); + IGRAPH_FINALLY_CLEAN(1); + PROTECT(edges=R_igraph_vector_int_to_SEXPp1(&c_edges)); + igraph_vector_int_destroy(&c_edges); + IGRAPH_FINALLY_CLEAN(1); + SET_VECTOR_ELT(r_result, 0, vertices); + SET_VECTOR_ELT(r_result, 1, edges); + SET_STRING_ELT(r_names, 0, Rf_mkChar("vertices")); + SET_STRING_ELT(r_names, 1, Rf_mkChar("edges")); + SET_NAMES(r_result, r_names); + UNPROTECT(3); + + UNPROTECT(1); + return(r_result); +} + /*-------------------------------------------/ / igraph_is_eulerian / /-------------------------------------------*/ diff --git a/src/vendor/cigraph/.travis.yml b/src/vendor/cigraph/.travis.yml index 295272b1d3..afce718b7f 100644 --- a/src/vendor/cigraph/.travis.yml +++ b/src/vendor/cigraph/.travis.yml @@ -76,17 +76,17 @@ jobs: - mkdir build && cd build - cmake .. -DIGRAPH_USE_INTERNAL_BLAS=OFF -DIGRAPH_USE_INTERNAL_LAPACK=OFF -DIGRAPH_USE_INTERNAL_ARPACK=OFF -DIGRAPH_USE_INTERNAL_GLPK=OFF -DIGRAPH_USE_INTERNAL_GMP=OFF -DIGRAPH_VERIFY_FINALLY_STACK=OFF -DCMAKE_BUILD_TYPE=Debug -DIGRAPH_PRINT_ARITH_HEADER=ON -DUSE_SANITIZER=Address - - name: "Linux ppc64" - os: linux - arch: ppc64le + # - name: "Linux ppc64" + # os: linux + # arch: ppc64le - - name: "Linux s390x" - os: linux - arch: s390x - # Do not enable ASan, as it leads to linking errors. - before_script: - - mkdir build && cd build - - cmake .. -DIGRAPH_USE_INTERNAL_BLAS=ON -DIGRAPH_USE_INTERNAL_LAPACK=ON -DIGRAPH_USE_INTERNAL_ARPACK=ON -DIGRAPH_USE_INTERNAL_GLPK=ON -DIGRAPH_USE_INTERNAL_GMP=ON -DIGRAPH_VERIFY_FINALLY_STACK=ON -DCMAKE_BUILD_TYPE=Debug -DIGRAPH_PRINT_ARITH_HEADER=ON + # - name: "Linux s390x" + # os: linux + # arch: s390x + # # Do not enable ASan, as it leads to linking errors. + # before_script: + # - mkdir build && cd build + # - cmake .. -DIGRAPH_USE_INTERNAL_BLAS=ON -DIGRAPH_USE_INTERNAL_LAPACK=ON -DIGRAPH_USE_INTERNAL_ARPACK=ON -DIGRAPH_USE_INTERNAL_GLPK=ON -DIGRAPH_USE_INTERNAL_GMP=ON -DIGRAPH_VERIFY_FINALLY_STACK=ON -DCMAKE_BUILD_TYPE=Debug -DIGRAPH_PRINT_ARITH_HEADER=ON #notifications: # email: diff --git a/src/vendor/cigraph/CHANGELOG.md b/src/vendor/cigraph/CHANGELOG.md index c1af9b9034..49e7103ec3 100644 --- a/src/vendor/cigraph/CHANGELOG.md +++ b/src/vendor/cigraph/CHANGELOG.md @@ -2,10 +2,46 @@ ## [master] +### Added + + - `igraph_bitset_update()` copies the contents of one bitset into another (experimental function). + - `igraph_vector_sort_ind()` (rename of `igraph_vector_qsort_ind()`). + - `igraph_vector_contains_sorted()` (rename of `igraph_vector_binsearch2()`). + - `igraph_vector_reverse_section()` reverses a contiguous section of a vector. + - `igraph_vector_rotate_left()` applies a cyclic permutation to a vector. + - `igraph_strvector_swap_elements()` swaps two strings in an `igraph_strvector_t`. + - `igraph_find_cycle()` finds a single cycle in a graph, if it exists (experimental function). + - `igraph_feedback_vertex_set()` finds a minimum feedback vertex set in a directed or undirected graph (experimental function). + +### Changed + + - `igraph_feedback_arc_set()` uses a much faster method for solving the exact minimum feedback arc set problem. The new method (`IGRAPH_FAS_EXACT_IP_CG`) is used by default (i.e. with `IGRAPH_FAS_EXACT_IP`), but the previous method is also kept available (`IGRAPH_FAS_EXACT_IP_TI`). + - `igraph_motifs_randesu()`, `igraph_motifs_randesu_callback()`, `igraph_motifs_randesu_estimate()` and `igraph_motifs_randesu_no()` now accept `NULL` for their `cut_prob` parameter, signifying that a complete search should be performed. + ### Fixed - `igraph_layout_drl()` and `igraph_layout_drl_3d()` would crash with an assertion failure when interrupted. This is now fixed. - Removed broken interruption support from `igraph_community_spinglass_single()`. + - In rare cases `igraph_community_multilevel()` could enter an infinite loop. This is now corrected. + - Fixed null-dereference in `igraph_community_voronoi()` when requesting `modularity` but not `membership`. + - Fixed null-dereference in `igraph_community_optimal_modularity()` when requesting `modularity` but not `membership` and passing a null graph or singleton graph. + - `igraph_layout_umap()` and `igraph_layout_umap_3d()` would crash when passing `distances=NULL` and `distances_are_weights=true`. This is now fixed. + - `igraph_layout_umap()` and `igraph_layout_umap_3d()` would crash on interruption. This is now fixed. + - `igraph_read_graph_pajek()` now warns about duplicate vertex IDs in input files. + - The documented `igraph_strvector_resize_min()` was missing from headers. + - `igraph_feedback_arc_set()` now validates the edge weights. + +### Deprecated + + - `igraph_minimum_spanning_tree_prim()` and `igraph_minimum_spanning_tree_unweighted()` are deprecated. Use `igraph_minimum_spanning_tree()` in conjunction with `igraph_subgraph_from_edges()` instead. + - `igraph_array3_t` and all associated functions are deprecated and scheduled for removal in igraph 1.0. + - `igraph_vector_qsort_ind()` is deprecated in favour of `igraph_vector_sort_ind()`. + - `igraph_vector_binsearch2()` is deprecated in favour of `igraph_vector_contains_sorted()`. + +### Other + + - Fixed multiple memory leaks in benchmark programs. + - Documentation improvements. ## [0.10.13] @@ -70,7 +106,7 @@ ### Changed - - `igraph_eigenvector_centrality()` no longer issues a warning when the input is directed and weighted. When using this function, keep in mind that eigenvector centrality is well-defined only for (strongly) connected graphs, and edges with a zero weights are effectively treated as absent. + - `igraph_eigenvector_centrality()` no longer issues a warning when the input is directed and weighted. When using this function, keep in mind that eigenvector centrality is well-defined only for (strongly) connected graphs, and edges with zero weights are effectively treated as absent. ### Deprecated @@ -419,7 +455,7 @@ Some of the highlights are: - The random number generator interface, `igraph_rng_type_t`, has been overhauled. Check the declaration of the type for details. - The default random number generator has been changed from Mersenne Twister to PCG32. - Functions related to spectral coarse graining (i.e. all functions starting with `igraph_scg_...`) were separated into a project of its own. If you wish to keep on using these functions, please refer to the repository hosting the spectral coarse graining code at https://github.com/igraph/igraph-scg . The spectral coarse graining code was updated to support igraph 0.10. - - Since `igraph_integer_t` aims to be the largest integer size that is feasible on a particular platform, there is no need for generic data types based on `long int` any more. The `long` variants of generic data types (e.g., `igraph_vector_long_t`) are therefore removed; you should use the corresponding `int` variant instead, whose elements are of type `igraph_integer_t`. + - Since `igraph_integer_t` aims to be the largest integer size that is feasible on a particular platform, there is no need for generic data types based on `long int` anymore. The `long` variants of generic data types (e.g., `igraph_vector_long_t`) are therefore removed; you should use the corresponding `int` variant instead, whose elements are of type `igraph_integer_t`. - Generic data types based on `float` were removed as they were not used anywhere in the library. - Several igraph functions that used to take a `long int` or return a `long int` now takes or returns an `igraph_integer_t` instead to make the APIs more consistent. Similarly, igraph functions that used `igraph_vector_t` for arguments that take or return _integral_ vectors (e.g., vertex or edge indices) now take `igraph_vector_int_t` instead. Graph-related functions where the API was changed due to this reason are listed below, one by one. - Similarly, igraph functions that used to accept the `long` variant of a generic igraph data type (e.g., `igraph_vector_long_t`) now take the `int` variant of the same data type. diff --git a/src/vendor/cigraph/CITATION.cff b/src/vendor/cigraph/CITATION.cff index 842c13a25e..9d902cb363 100644 --- a/src/vendor/cigraph/CITATION.cff +++ b/src/vendor/cigraph/CITATION.cff @@ -27,7 +27,7 @@ authors: family-names: Noom identifiers: - type: doi - value: 10.5281/zenodo.4319996 + value: 10.5281/zenodo.3630268 description: Zenodo repository-code: 'https://github.com/igraph/igraph' url: 'https://igraph.org' diff --git a/src/vendor/cigraph/CMakeLists.txt b/src/vendor/cigraph/CMakeLists.txt index 26256d5a90..715eaa9d5d 100644 --- a/src/vendor/cigraph/CMakeLists.txt +++ b/src/vendor/cigraph/CMakeLists.txt @@ -5,7 +5,7 @@ # * SKIP_REGULAR_EXPRESSION to handle skipped tests properly (3.16) # * CheckLinkerFlag for HAVE_NEW_DTAGS test (3.18) # * cmake -E cat (3.18) -cmake_minimum_required(VERSION 3.18...3.29) +cmake_minimum_required(VERSION 3.18...3.30) # Add etc/cmake to CMake's search path so we can put our private stuff there list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/etc/cmake) diff --git a/src/vendor/cigraph/CODE_OF_CONDUCT.md b/src/vendor/cigraph/CODE_OF_CONDUCT.md deleted file mode 100644 index 3402d546ed..0000000000 --- a/src/vendor/cigraph/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,178 +0,0 @@ -# igraph Code of Conduct - -## Introduction - -This code of conduct applies to all spaces managed by the igraph project, -including all public and private mailing lists, issue trackers, wikis, blogs, -Twitter, and any other communication channel used by our community. Any events -related to our community shall also be bound by this code of conduct or a very -similar variant thereof. - -This code of conduct should be honored by everyone who participates in the -igraph community formally or informally, or claims any affiliation with the -project, in any project-related activities, and, especially, when representing -the project, in any capacity. - -This code of conduct is neither exhaustive nor complete. It serves to distill -our common understanding of a collaborative, shared environment and goals. -Please try to follow this code in spirit as much as in letter, to create -a friendly and productive environment that enriches the surrounding community. - -## Specific guidelines - -We strive to: - -1. Be open. We invite anyone to participate in our community. We prefer to use - public methods of communication for project-related messages, unless - discussing something sensitive. This applies to messages for help or - project-related support, too; not only is a public-support request much more - likely to result in an answer to a question, it also ensures that any - inadvertent mistakes in answering are more easily detected and corrected. - -2. Be empathetic, welcoming, friendly, and patient. We work together to resolve - conflict, and assume good intentions. We may all experience some frustration - from time to time, but we do not allow frustration to turn into a personal - attack. A community where people feel uncomfortable or threatened is not a - productive one. - -3. Be collaborative. Our work will be used by other people, and in turn we will - depend on the work of others. When we make something for the benefit of the - project, we are willing to explain to others how it works, so that they can - build on the work to make it even better. Any decision we make will affect - users and colleagues, and we take those consequences seriously when making - decisions. - -4. Be inquisitive. Nobody knows everything! Asking questions early avoids many - problems later, so we encourage questions, although we may direct them to - the appropriate forum. We will try hard to be responsive and helpful. - -5. Be careful in the words that we choose. We are careful and respectful in - our communication and we take responsibility for our own words. Be kind to - others. Do not insult or put down other participants. We do not tolerate - harassment or other exclusionary behavior, such as: - - * Violent threats or language directed against another person. - - * Sexist, racist, or otherwise discriminatory jokes and language. - - * Posting sexually explicit or violent material. - - * Posting (or threatening to post) other people’s personally identifying - information (“doxing”). - - * Sharing private content, such as emails sent privately or non-publicly, - or unlogged forums, such as IRC channel history, without the sender’s consent. - - * Personal insults, especially those using racist or sexist terms. - - * Unwelcome sexual attention. - - * Excessive profanity. Please avoid swearwords; people differ greatly in - their sensitivity to swearing. - - * Repeated harassment of others. In general, if someone asks you to stop, - then stop. - - * Advocating for, or encouraging, any of the above behavior. - -## Diversity statement - -The igraph project welcomes and encourages participation by everyone. We are -committed to being a community that everyone enjoys being part of. Although -we may not always be able to accommodate each individual’s preferences, we try -our best to treat everyone kindly. - -No matter how you identify yourself or how others perceive you: we welcome you. -Though no list can hope to be comprehensive, we explicitly honor diversity in: -age, culture, ethnicity, genotype, gender identity or expression, language, -national origin, neurotype, phenotype, political beliefs, profession, race, -religion, sexual orientation, socioeconomic status, subculture and technical -ability, to the extent that these do not conflict with this code of conduct. - -Though we welcome people fluent in all languages, igraph development is -conducted in English. - -Standards for behavior in the igraph community are detailed in the Code of -Conduct above. Participants in our community should uphold these standards -in all their interactions and help others to do so as well (see next section). - -## Reporting guidelines - -We know that it is painfully common for internet communication to start at or -devolve into obvious and flagrant abuse. We also recognize that sometimes -people may have a bad day, or be unaware of some of the guidelines in this Code -of Conduct. Please keep this in mind when deciding on how to respond to a -breach of this Code. - -For clearly flagrant breaches, report those to the igraph organisation -(see below). For possibly unintentional breaches, you may reply to the person -and point out this Code of Conduct (either in public or in private, whatever is -most appropriate). If you would prefer not to do that, please feel free to -report to the igraph organisation directly, or ask the organisation for -advice, in confidence. - -You can report issues to the igraph organisation, at . -Currently, the following persons will receive your report: - -* Gábor Csárdi - -* Tamás Nepusz - -* Szabolcs Horvát - -* Vincent Traag - -If your report involves any of the above mentioned persons, or if they feel -they have a conflict of interest in handling it, they will recuse themselves -from considering your report. Alternatively, if, for any reason, you feel -uncomfortable making a report to the organisation directly, then you can also -contact any of the above mentioned persons individually. - -## Incident reporting - -We will investigate and respond to all complaints. The igraph organisation will -protect the identity of the reporter, and treat the content of complaints as -confidential (unless the reporter agrees otherwise). - -In case of flagrant breaches, e.g., personal threats or violent, sexist or -racist language, we will immediately disconnect the originator from igraph. In -particular, the organisation will - -1. Immediately disconnect the originator from all igraph communication channels. - -2. Revoke any granted permissions from the originator. - -3. Reply to the reporter that their report has been received and that the - originator has been disconnected. - -4. In every case, the moderator should make a reasonable effort to contact the - originator, and tell them specifically how their language or actions qualify - as a “flagrant breach”. The moderator should also say that, if the - originator believes this is unfair or they want to be reconnected to igraph, - they have the right to ask for a review, as below, by the igraph - organisation. - -5. The igraph organisation will formally review and sign off on all cases - where this mechanism has been applied to make sure it is not being - used to control ordinary heated disagreement. - -In cases not involving flagrant breaches of this code of conduct, the process -for acting on any received code of conduct violation report will be: - -1. acknowledgement that the report has been received - -2. reasonable discussion/feedback - -3. mediation (if feedback didn’t help, and only if both reporter and reportee - agree to this) - -The organisation will respond to any report as soon as possible, and at most -within 5 working days. - -## Endnotes - -This Code of Conduct is inspired by [the SciPy Code of Conduct](https://docs.scipy.org/doc/scipy/reference/dev/conduct/code_of_conduct.html). - -The current organisation of the igraph community is rudimentary. A more -professional organisation may develop in the future, at which point the -procedure of handling incident reports will also be further formalized. diff --git a/src/vendor/cigraph/azure-pipelines.yml b/src/vendor/cigraph/azure-pipelines.yml index 18a34e08d5..c5ed7b6e06 100644 --- a/src/vendor/cigraph/azure-pipelines.yml +++ b/src/vendor/cigraph/azure-pipelines.yml @@ -2,6 +2,7 @@ pool: vmImage: 'ubuntu-latest' variables: + CMAKE_COLOR_DIAGNOSTICS: ON CMAKE_GENERATOR: Ninja CCACHE_DIR: $(Pipeline.Workspace)/ccache CCACHE_MAXSIZE: 256M diff --git a/src/vendor/cigraph/include/igraph_adjlist.h b/src/vendor/cigraph/include/igraph_adjlist.h index 49a584cd11..e6125fab4c 100644 --- a/src/vendor/cigraph/include/igraph_adjlist.h +++ b/src/vendor/cigraph/include/igraph_adjlist.h @@ -66,11 +66,12 @@ IGRAPH_EXPORT igraph_error_t igraph_adjlist_replace_edge(igraph_adjlist_t* al, i * \define igraph_adjlist_get * \brief Query a vector in an adjacency list. * - * Returns a pointer to an igraph_vector_int_t object from an + * Returns a pointer to an \ref igraph_vector_int_t object from an * adjacency list. The vector can be modified as desired. + * * \param al The adjacency list object. * \param no The vertex whose adjacent vertices will be returned. - * \return Pointer to the igraph_vector_int_t object. + * \return Pointer to the \ref igraph_vector_int_t object. * * Time complexity: O(1). */ diff --git a/src/vendor/cigraph/include/igraph_array_pmt.h b/src/vendor/cigraph/include/igraph_array_pmt.h index 9add5e8476..8cbcfb4337 100644 --- a/src/vendor/cigraph/include/igraph_array_pmt.h +++ b/src/vendor/cigraph/include/igraph_array_pmt.h @@ -36,19 +36,19 @@ typedef struct TYPE(igraph_array3) { #define ARRAY3(m,i,j,k) ((m).data.stor_begin[(m).n1n2*(k)+(m).n1*(j)+(i)]) #endif -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, init)( +IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, init)( TYPE(igraph_array3) *a, igraph_integer_t n1, igraph_integer_t n2, igraph_integer_t n3); -IGRAPH_EXPORT void FUNCTION(igraph_array3, destroy)(TYPE(igraph_array3) *a); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_array3, size)(const TYPE(igraph_array3) *a); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_array3, n)( +IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, destroy)(TYPE(igraph_array3) *a); +IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_array3, size)(const TYPE(igraph_array3) *a); +IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_array3, n)( const TYPE(igraph_array3) *a, igraph_integer_t idx); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, resize)( +IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, resize)( TYPE(igraph_array3) *a, igraph_integer_t n1, igraph_integer_t n2, igraph_integer_t n3); -IGRAPH_EXPORT void FUNCTION(igraph_array3, null)(TYPE(igraph_array3) *a); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_array3, sum)(const TYPE(igraph_array3) *a); -IGRAPH_EXPORT void FUNCTION(igraph_array3, scale)(TYPE(igraph_array3) *a, BASE by); -IGRAPH_EXPORT void FUNCTION(igraph_array3, fill)(TYPE(igraph_array3) *a, BASE e); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, update)(TYPE(igraph_array3) *to, +IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, null)(TYPE(igraph_array3) *a); +IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_array3, sum)(const TYPE(igraph_array3) *a); +IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, scale)(TYPE(igraph_array3) *a, BASE by); +IGRAPH_DEPRECATED IGRAPH_EXPORT void FUNCTION(igraph_array3, fill)(TYPE(igraph_array3) *a, BASE e); +IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_array3, update)(TYPE(igraph_array3) *to, const TYPE(igraph_array3) *from); diff --git a/src/vendor/cigraph/include/igraph_attributes.h b/src/vendor/cigraph/include/igraph_attributes.h index 9773ce78df..985b55a3aa 100644 --- a/src/vendor/cigraph/include/igraph_attributes.h +++ b/src/vendor/cigraph/include/igraph_attributes.h @@ -24,7 +24,6 @@ #ifndef IGRAPH_ATTRIBUTES_H #define IGRAPH_ATTRIBUTES_H -#include "igraph_config.h" #include "igraph_decls.h" #include "igraph_error.h" #include "igraph_datatype.h" diff --git a/src/vendor/cigraph/include/igraph_bitset.h b/src/vendor/cigraph/include/igraph_bitset.h index fcf0937ad0..c7f7daef94 100644 --- a/src/vendor/cigraph/include/igraph_bitset.h +++ b/src/vendor/cigraph/include/igraph_bitset.h @@ -236,6 +236,7 @@ typedef struct { IGRAPH_EXPORT igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_integer_t size); IGRAPH_EXPORT void igraph_bitset_destroy(igraph_bitset_t *bitset); IGRAPH_EXPORT igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitset_t *src); +IGRAPH_EXPORT igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t *src); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_capacity(const igraph_bitset_t *bitset); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset); IGRAPH_EXPORT igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_integer_t capacity); diff --git a/src/vendor/cigraph/include/igraph_constants.h b/src/vendor/cigraph/include/igraph_constants.h index 8a7dbcfb12..8deea5f18d 100644 --- a/src/vendor/cigraph/include/igraph_constants.h +++ b/src/vendor/cigraph/include/igraph_constants.h @@ -179,9 +179,14 @@ typedef enum { IGRAPH_BARABASI_BAG = 0, } igraph_barabasi_algorithm_t; typedef enum { IGRAPH_FAS_EXACT_IP = 0, - IGRAPH_FAS_APPROX_EADES + IGRAPH_FAS_APPROX_EADES, + IGRAPH_FAS_EXACT_IP_CG, + IGRAPH_FAS_EXACT_IP_TI } igraph_fas_algorithm_t; +typedef enum { IGRAPH_FVS_EXACT_IP = 0 + } igraph_fvs_algorithm_t; + typedef enum { IGRAPH_SUBGRAPH_AUTO = 0, IGRAPH_SUBGRAPH_COPY_AND_DELETE, IGRAPH_SUBGRAPH_CREATE_FROM_SCRATCH diff --git a/src/vendor/cigraph/include/igraph_cycles.h b/src/vendor/cigraph/include/igraph_cycles.h index dd5870003b..5b590f1ad8 100644 --- a/src/vendor/cigraph/include/igraph_cycles.h +++ b/src/vendor/cigraph/include/igraph_cycles.h @@ -2,6 +2,7 @@ #ifndef IGRAPH_CYCLES_H #define IGRAPH_CYCLES_H +#include "igraph_constants.h" #include "igraph_datatype.h" #include "igraph_decls.h" #include "igraph_error.h" @@ -25,6 +26,12 @@ IGRAPH_EXPORT igraph_error_t igraph_minimum_cycle_basis( igraph_bool_t use_cycle_order, const igraph_vector_t *weights); +IGRAPH_EXPORT igraph_error_t igraph_find_cycle( + const igraph_t *graph, + igraph_vector_int_t *vertices, + igraph_vector_int_t *edges, + igraph_neimode_t mode); + __END_DECLS #endif diff --git a/src/vendor/cigraph/include/igraph_interface.h b/src/vendor/cigraph/include/igraph_interface.h index 88731a39bb..27c642a3e1 100644 --- a/src/vendor/cigraph/include/igraph_interface.h +++ b/src/vendor/cigraph/include/igraph_interface.h @@ -73,7 +73,7 @@ IGRAPH_EXPORT igraph_error_t igraph_get_all_eids_between(const igraph_t *graph, igraph_integer_t source, igraph_integer_t target, igraph_bool_t directed); IGRAPH_EXPORT igraph_error_t igraph_incident(const igraph_t *graph, igraph_vector_int_t *eids, igraph_integer_t vid, igraph_neimode_t mode); -IGRAPH_EXPORT igraph_error_t igraph_is_same_graph(const igraph_t *graph1, const igraph_t *igraph2, igraph_bool_t *res); +IGRAPH_EXPORT igraph_error_t igraph_is_same_graph(const igraph_t *graph1, const igraph_t *graph2, igraph_bool_t *res); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_i_property_cache_get_bool(const igraph_t *graph, igraph_cached_property_t prop); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_i_property_cache_has(const igraph_t *graph, igraph_cached_property_t prop); diff --git a/src/vendor/cigraph/include/igraph_structural.h b/src/vendor/cigraph/include/igraph_structural.h index e9df9672ec..1ff600b164 100644 --- a/src/vendor/cigraph/include/igraph_structural.h +++ b/src/vendor/cigraph/include/igraph_structural.h @@ -95,9 +95,9 @@ IGRAPH_EXPORT igraph_error_t igraph_is_independent_vertex_set(const igraph_t *gr igraph_bool_t *res); IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree(const igraph_t *graph, igraph_vector_int_t *res, const igraph_vector_t *weights); -IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, +IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, igraph_t *mst); -IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst, +IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t igraph_minimum_spanning_tree_prim(const igraph_t *graph, igraph_t *mst, const igraph_vector_t *weights); IGRAPH_EXPORT igraph_error_t igraph_random_spanning_tree(const igraph_t *graph, igraph_vector_int_t *res, igraph_integer_t vid); @@ -131,8 +131,13 @@ IGRAPH_EXPORT igraph_error_t igraph_degree_correlation_vector( igraph_neimode_t from_mode, igraph_neimode_t to_mode, igraph_bool_t directed_neighbors); -IGRAPH_EXPORT igraph_error_t igraph_feedback_arc_set(const igraph_t *graph, igraph_vector_int_t *result, - const igraph_vector_t *weights, igraph_fas_algorithm_t algo); +IGRAPH_EXPORT igraph_error_t igraph_feedback_arc_set( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *weights, igraph_fas_algorithm_t algo); + +IGRAPH_EXPORT igraph_error_t igraph_feedback_vertex_set( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *vertex_weights, igraph_fvs_algorithm_t algo); /* -------------------------------------------------- */ /* Spectral Properties */ @@ -149,7 +154,7 @@ IGRAPH_EXPORT igraph_error_t igraph_feedback_arc_set(const igraph_t *graph, igra * are used according to the \p mode parameter. * * \enumval IGRAPH_LAPLACIAN_UNNORMALIZED Unnormalized Laplacian, L = D - A. - * \enumval IGRAPH_LAPLACIAN_SYMMETRIC Symmetric normalized Laplacian, L = I - D^(-1/2) A D^(-1/2). + * \enumval IGRAPH_LAPLACIAN_SYMMETRIC Symmetrically normalized Laplacian, L = I - D^(-1/2) A D^(-1/2). * \enumval IGRAPH_LAPLACIAN_LEFT Left-stochastic normalized Laplacian, L = I - D^-1 A. * \enumval IGRAPH_LAPLACIAN_RIGHT Right-stochastic normalized Laplacian, L = I - A D^-1. */ diff --git a/src/vendor/cigraph/include/igraph_strvector.h b/src/vendor/cigraph/include/igraph_strvector.h index f7d2d59b90..c01b695d3b 100644 --- a/src/vendor/cigraph/include/igraph_strvector.h +++ b/src/vendor/cigraph/include/igraph_strvector.h @@ -89,6 +89,7 @@ IGRAPH_EXPORT igraph_error_t igraph_strvector_merge( igraph_strvector_t *to, igraph_strvector_t *from); IGRAPH_EXPORT igraph_error_t igraph_strvector_resize( igraph_strvector_t* v, igraph_integer_t newsize); +IGRAPH_EXPORT void igraph_strvector_resize_min(igraph_strvector_t *sv); IGRAPH_EXPORT igraph_error_t igraph_strvector_push_back(igraph_strvector_t *v, const char *value); IGRAPH_EXPORT igraph_error_t igraph_strvector_push_back_len(igraph_strvector_t *v, @@ -103,6 +104,9 @@ IGRAPH_EXPORT igraph_error_t igraph_strvector_index(const igraph_strvector_t *v, IGRAPH_EXPORT igraph_error_t igraph_strvector_reserve(igraph_strvector_t *sv, igraph_integer_t capacity); +IGRAPH_EXPORT void igraph_strvector_swap_elements(igraph_strvector_t *sv, + igraph_integer_t i, igraph_integer_t j); + IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_strvector_add(igraph_strvector_t *v, const char *value); IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t igraph_strvector_copy( igraph_strvector_t *to, const igraph_strvector_t *from); diff --git a/src/vendor/cigraph/include/igraph_vector_list.h b/src/vendor/cigraph/include/igraph_vector_list.h index f1d299dc94..dc45323b18 100644 --- a/src/vendor/cigraph/include/igraph_vector_list.h +++ b/src/vendor/cigraph/include/igraph_vector_list.h @@ -58,12 +58,6 @@ __BEGIN_DECLS #define IGRAPH_VECTOR_LIST_INIT_FINALLY(v, size) \ do { IGRAPH_CHECK(igraph_vector_list_init(v, size)); \ IGRAPH_FINALLY(igraph_vector_list_destroy, v); } while (0) -#define IGRAPH_VECTOR_BOOL_LIST_INIT_FINALLY(v, size) \ - do { IGRAPH_CHECK(igraph_vector_bool_list_init(v, size)); \ - IGRAPH_FINALLY(igraph_vector_bool_list_destroy, v); } while (0) -#define IGRAPH_VECTOR_CHAR_LIST_INIT_FINALLY(v, size) \ - do { IGRAPH_CHECK(igraph_vector_char_list_init(v, size)); \ - IGRAPH_FINALLY(igraph_vector_char_list_destroy, v); } while (0) #define IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(v, size) \ do { IGRAPH_CHECK(igraph_vector_int_list_init(v, size)); \ IGRAPH_FINALLY(igraph_vector_int_list_destroy, v); } while (0) diff --git a/src/vendor/cigraph/include/igraph_vector_pmt.h b/src/vendor/cigraph/include/igraph_vector_pmt.h index c303a7802a..4ec3f877c8 100644 --- a/src/vendor/cigraph/include/igraph_vector_pmt.h +++ b/src/vendor/cigraph/include/igraph_vector_pmt.h @@ -26,9 +26,9 @@ /*--------------------*/ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init)( - TYPE(igraph_vector)* v, igraph_integer_t size); + TYPE(igraph_vector) *v, igraph_integer_t size); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init_array)( - TYPE(igraph_vector)* v, const BASE* data, igraph_integer_t length); + TYPE(igraph_vector) *v, const BASE *data, igraph_integer_t length); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, init_copy)( TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from); @@ -39,7 +39,7 @@ IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t FUNCTION(igraph_vector, init_seq) IGRAPH_EXPORT IGRAPH_DEPRECATED igraph_error_t FUNCTION(igraph_vector, copy)( TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from); -IGRAPH_EXPORT void FUNCTION(igraph_vector, destroy)(TYPE(igraph_vector)* v); +IGRAPH_EXPORT void FUNCTION(igraph_vector, destroy)(TYPE(igraph_vector) *v); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector)*v); @@ -57,7 +57,7 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, capa * \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 + * \verbatim VECTOR(v)[10] = 5; \endverbatim * * Note that there are no range checks right now. * @@ -68,22 +68,22 @@ IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t FUNCTION(igraph_vector, capa #define VECTOR(v) ((v).stor_begin) #endif -IGRAPH_EXPORT IGRAPH_DEPRECATED BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector)* v, igraph_integer_t pos); -IGRAPH_EXPORT IGRAPH_DEPRECATED BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector)* v, igraph_integer_t pos); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector)* v, igraph_integer_t pos); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE* FUNCTION(igraph_vector, get_ptr)(const TYPE(igraph_vector)* v, igraph_integer_t pos); -IGRAPH_EXPORT void FUNCTION(igraph_vector, set)(TYPE(igraph_vector)* v, igraph_integer_t pos, BASE value); +IGRAPH_EXPORT IGRAPH_DEPRECATED BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector) *v, igraph_integer_t pos); +IGRAPH_EXPORT IGRAPH_DEPRECATED BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector) *v, igraph_integer_t pos); +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE* FUNCTION(igraph_vector, get_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos); +IGRAPH_EXPORT void FUNCTION(igraph_vector, set)(TYPE(igraph_vector) *v, igraph_integer_t pos, BASE value); IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE BASE FUNCTION(igraph_vector, tail)(const TYPE(igraph_vector) *v); /*-----------------------*/ /* Initializing elements */ /*-----------------------*/ -IGRAPH_EXPORT void FUNCTION(igraph_vector, null)(TYPE(igraph_vector)* v); -IGRAPH_EXPORT void FUNCTION(igraph_vector, fill)(TYPE(igraph_vector)* v, BASE e); +IGRAPH_EXPORT void FUNCTION(igraph_vector, null)(TYPE(igraph_vector) *v); +IGRAPH_EXPORT void FUNCTION(igraph_vector, fill)(TYPE(igraph_vector) *v, BASE e); #ifndef NOTORDERED -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, range)(TYPE(igraph_vector)*v, BASE start, BASE end); +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, range)(TYPE(igraph_vector) *v, BASE start, BASE end); #endif /*-----------------------*/ @@ -98,7 +98,7 @@ IGRAPH_EXPORT const TYPE(igraph_vector) *FUNCTION(igraph_vector, view)(const TYP /* Copying vectors */ /*-----------------------*/ -IGRAPH_EXPORT void FUNCTION(igraph_vector, copy_to)(const TYPE(igraph_vector) *v, BASE* to); +IGRAPH_EXPORT void FUNCTION(igraph_vector, copy_to)(const TYPE(igraph_vector) *v, BASE *to); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, update)(TYPE(igraph_vector) *to, const TYPE(igraph_vector) *from); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, append)(TYPE(igraph_vector) *to, @@ -112,6 +112,10 @@ IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, swap)(TYPE(igraph_vector) * IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, swap_elements)( TYPE(igraph_vector) *v, igraph_integer_t i, igraph_integer_t j); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v); +IGRAPH_EXPORT void FUNCTION(igraph_vector, reverse_section)( + TYPE(igraph_vector) *v, igraph_integer_t from, igraph_integer_t to); +IGRAPH_EXPORT void FUNCTION(igraph_vector, rotate_left)( + TYPE(igraph_vector) *v, igraph_integer_t n); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, permute)(TYPE(igraph_vector) *v, const igraph_vector_int_t *ind); IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, shuffle)(TYPE(igraph_vector) *v); @@ -211,7 +215,9 @@ IGRAPH_EXPORT igraph_bool_t FUNCTION(igraph_vector, binsearch_slice)( igraph_integer_t start, igraph_integer_t end); IGRAPH_EXPORT igraph_bool_t FUNCTION(igraph_vector, binsearch)( const TYPE(igraph_vector) *v, BASE what, igraph_integer_t *pos); -IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, binsearch2)( +IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, contains_sorted)( + const TYPE(igraph_vector) *v, BASE what); +IGRAPH_DEPRECATED IGRAPH_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t FUNCTION(igraph_vector, binsearch2)( const TYPE(igraph_vector) *v, BASE what); #endif @@ -244,9 +250,12 @@ IGRAPH_EXPORT void FUNCTION(igraph_vector, remove_section)( IGRAPH_EXPORT void FUNCTION(igraph_vector, sort)(TYPE(igraph_vector) *v); IGRAPH_EXPORT void FUNCTION(igraph_vector, reverse_sort)(TYPE(igraph_vector) *v); -IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, qsort_ind)( +IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, sort_ind)( const TYPE(igraph_vector) *v, igraph_vector_int_t *inds, igraph_order_t order); +IGRAPH_DEPRECATED IGRAPH_EXPORT igraph_error_t FUNCTION(igraph_vector, qsort_ind)( + const TYPE(igraph_vector) *v, igraph_vector_int_t *inds, igraph_order_t order); + #endif /*-----------*/ diff --git a/src/vendor/cigraph/interfaces/functions.yaml b/src/vendor/cigraph/interfaces/functions.yaml index cc56a684b7..7f7f02ee21 100644 --- a/src/vendor/cigraph/interfaces/functions.yaml +++ b/src/vendor/cigraph/interfaces/functions.yaml @@ -578,7 +578,7 @@ igraph_distances_floyd_warshall: PARAMS: |- GRAPH graph, OUT MATRIX res, VERTEX_SELECTOR from=ALL, VERTEX_SELECTOR to=ALL, EDGEWEIGHTS weights=NULL, NEIMODE mode=OUT, - FWALGORITHM method + FWALGORITHM method=AUTOMATIC DEPS: from ON graph, to ON graph, weights ON graph igraph_voronoi: @@ -839,6 +839,10 @@ igraph_feedback_arc_set: PARAMS: GRAPH graph, OUT EDGE_INDICES result, EDGEWEIGHTS weights=NULL, FAS_ALGORITHM algo=APPROX_EADES DEPS: result ON graph, weights ON graph +igraph_feedback_vertex_set: + PARAMS: GRAPH graph, OUT VERTEX_INDICES result, VERTEXWEIGHTS weights=NULL, FVS_ALGORITHM algo=EXACT_IP + DEPS: result ON graph, weights ON graph + igraph_is_loop: PARAMS: GRAPH graph, OUT VECTOR_BOOL res, EDGE_SELECTOR es=ALL DEPS: es ON graph @@ -1949,15 +1953,15 @@ igraph_write_graph_dot: ####################################### igraph_motifs_randesu: - PARAMS: GRAPH graph, OUT VECTOR hist, INTEGER size=3, VECTOR cut_prob + PARAMS: GRAPH graph, OUT VECTOR hist, INTEGER size=3, OPTIONAL VECTOR cut_prob igraph_motifs_randesu_estimate: PARAMS: |- - GRAPH graph, OUT INTEGER est, INTEGER size=3, VECTOR cut_prob, + GRAPH graph, OUT INTEGER est, INTEGER size=3, OPTIONAL VECTOR cut_prob, INTEGER sample_size, OPTIONAL VECTOR_INT sample igraph_motifs_randesu_no: - PARAMS: GRAPH graph, OUT INTEGER no, INTEGER size=3, VECTOR cut_prob + PARAMS: GRAPH graph, OUT INTEGER no, INTEGER size=3, OPTIONAL VECTOR cut_prob igraph_dyad_census: PARAMS: GRAPH graph, OUT REAL mut, OUT REAL asym, OUT REAL null @@ -2498,6 +2502,16 @@ igraph_eigen_matrix_symmetric: igraph_solve_lsap: PARAMS: MATRIX c, INTEGER n, OUT VECTOR_INT p +####################################### +# Finding cycles +####################################### + +igraph_find_cycle: + PARAMS: |- + GRAPH graph, OPTIONAL OUT VERTEX_INDICES vertices, OPTIONAL OUT EDGE_INDICES edges, + NEIMODE mode + DEPS: vertices ON graph, edges ON graph + ####################################### # Eulerian functions ####################################### diff --git a/src/vendor/cigraph/interfaces/types.yaml b/src/vendor/cigraph/interfaces/types.yaml index 3c15618944..06d66dd4ee 100644 --- a/src/vendor/cigraph/interfaces/types.yaml +++ b/src/vendor/cigraph/interfaces/types.yaml @@ -339,6 +339,11 @@ FAS_ALGORITHM: CTYPE: igraph_fas_algorithm_t FLAGS: ENUM +FVS_ALGORITHM: + # Enum representing feedback vertex set algorithms + CTYPE: igraph_fvs_algorithm_t + FLAGS: ENUM + FWALGORITHM: # Enum that describes the variant of the Floyd-Warshall algorithm to use in # Floyd-Warshall graph distances computing function diff --git a/src/vendor/cigraph/src/cliques/cliquer/cliquer.c b/src/vendor/cigraph/src/cliques/cliquer/cliquer.c index 218e16a1d9..01baed27e4 100644 --- a/src/vendor/cigraph/src/cliques/cliquer/cliquer.c +++ b/src/vendor/cigraph/src/cliques/cliquer/cliquer.c @@ -17,7 +17,7 @@ #include "cliquer.h" -#include "config.h" +#include "config.h" /* IGRAPH_THREAD_LOCAL */ /* Default cliquer options */ IGRAPH_THREAD_LOCAL clique_options clique_default_options = { diff --git a/src/vendor/cigraph/src/cliques/cliquer_wrapper.c b/src/vendor/cigraph/src/cliques/cliquer_wrapper.c index 7e2ca16df2..25002f2eca 100644 --- a/src/vendor/cigraph/src/cliques/cliquer_wrapper.c +++ b/src/vendor/cigraph/src/cliques/cliquer_wrapper.c @@ -23,7 +23,7 @@ #include "cliques/cliquer_internal.h" #include "cliques/cliquer/cliquer.h" -#include "config.h" +#include "config.h" /* IGRAPH_THREAD_LOCAL */ #include diff --git a/src/vendor/cigraph/src/cliques/maximal_cliques_template.h b/src/vendor/cigraph/src/cliques/maximal_cliques_template.h index be0824bc25..1f46fc2c1e 100644 --- a/src/vendor/cigraph/src/cliques/maximal_cliques_template.h +++ b/src/vendor/cigraph/src/cliques/maximal_cliques_template.h @@ -224,7 +224,7 @@ igraph_error_t FUNCTION(igraph_maximal_cliques, SUFFIX)( IGRAPH_VECTOR_INT_INIT_FINALLY(&rank, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&coreness, no_of_nodes); IGRAPH_CHECK(igraph_coreness(graph, &coreness, /*mode=*/ IGRAPH_ALL)); - IGRAPH_CHECK(igraph_vector_int_qsort_ind(&coreness, &order, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_int_sort_ind(&coreness, &order, IGRAPH_ASCENDING)); for (ii = 0; ii < no_of_nodes; ii++) { igraph_integer_t v = VECTOR(order)[ii]; VECTOR(rank)[v] = ii; diff --git a/src/vendor/cigraph/src/community/community_misc.c b/src/vendor/cigraph/src/community/community_misc.c index 5666944d22..a283991f49 100644 --- a/src/vendor/cigraph/src/community/community_misc.c +++ b/src/vendor/cigraph/src/community/community_misc.c @@ -28,6 +28,30 @@ #include #include +/** + * \section about_community + * + * + * Community detection is concerned with clustering the vertices of networks + * into tightly connected subgraphs called "communities". The following + * references provide a good introduction to the topic of community detection: + * + * + * + * S. Fortunato: + * "Community Detection in Graphs". + * Physics Reports 486, no. 3–5 (2010): 75–174. + * https://doi.org/16/j.physrep.2009.11.002. + * + * + * + * S. Fortunato and D. Hric: + * "Community Detection in Networks: A User Guide". + * Physics Reports 659 (2016): 1–44. + * https://doi.org/10.1016/j.physrep.2016.09.002. + * + */ + /** * \function igraph_community_to_membership * \brief Creates a membership vector from a community structure dendrogram. @@ -313,7 +337,7 @@ static igraph_error_t igraph_i_split_join_distance(const igraph_vector_int_t *v1 * of cluster \c i. Then the entropy of the clustering is * * - * H(C) = - \sum_i p_i log p_i + * H(C) = - sum_i p_i log p_i * * * Similarly, we can define the joint entropy of two clusterings \c C_1 and \c C_2 @@ -321,7 +345,7 @@ static igraph_error_t igraph_i_split_join_distance(const igraph_vector_int_t *v1 * in the first clustering and cluster \c j in the second one: * * - * H(C_1, C_2) = - \sum_ii p_ij log p_ij + * H(C_1, C_2) = - sum_ii p_ij log p_ij * * * The mutual information of \c C_1 and \c C_2 is then diff --git a/src/vendor/cigraph/src/community/edge_betweenness.c b/src/vendor/cigraph/src/community/edge_betweenness.c index 16b64f186f..493508039e 100644 --- a/src/vendor/cigraph/src/community/edge_betweenness.c +++ b/src/vendor/cigraph/src/community/edge_betweenness.c @@ -198,7 +198,7 @@ static igraph_error_t igraph_i_community_eb_get_merges2(const igraph_t *graph, * 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 n+1, etc. The matrix will be resized as needed. + * component n + 1, etc. The matrix will be resized as needed. * \param bridges Pointer to an initialized vector of \c NULL. If not * \c NULL then the indices into \p edges of all edges which caused * one of the merges will be put here. This is equal to all edge removals @@ -342,10 +342,7 @@ static igraph_integer_t igraph_i_vector_which_max_not_null(const igraph_vector_t * \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). https://doi.org/10.1073/pnas.122653799 + * in the network, known as the Grivan-Newman algorithm. * * * The idea is that the betweenness of the edges connecting two @@ -363,6 +360,15 @@ static igraph_integer_t igraph_i_vector_which_max_not_null(const igraph_vector_t * of betweenness and modularity are used, however, only splits into * \em weakly connected components are detected. * + * + * Reference: + * + * + * M. Girvan and M. E. J. Newman: + * Community structure in social and biological networks. + * Proc. Nat. Acad. Sci. USA 99, 7821-7826 (2002). + * https://doi.org/10.1073/pnas.122653799 + * * \param graph The input graph. * \param removed_edges Pointer to an initialized vector, the result will be * stored here, the IDs of the removed edges in the order of their diff --git a/src/vendor/cigraph/src/community/leading_eigenvector.c b/src/vendor/cigraph/src/community/leading_eigenvector.c index 91b88c4fbf..074dd6ccd9 100644 --- a/src/vendor/cigraph/src/community/leading_eigenvector.c +++ b/src/vendor/cigraph/src/community/leading_eigenvector.c @@ -45,13 +45,14 @@ * eigenvectors of matrices, Phys Rev E 74:036104 (2006). * * - * 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 configuration model 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. + * The heart of the method is the definition of the modularity matrix + * B = A - P, \c A being the adjacency matrix of the (undirected) + * network, and \c P contains the probability that certain edges are + * present according to the configuration model. In + * other words, a \c P_ij element of \c P is the probability that there is an + * edge between vertices \c i and \c j in a random network in which the + * degrees of all vertices are the same as in the input graph. See + * \ref igraph_modularity_matrix() for more details. * * * The leading eigenvector method works by calculating the eigenvector @@ -252,11 +253,11 @@ static void igraph_i_error_handler_none(const char *reason, const char *file, * community detection functions in igraph, the integers in this matrix * represent community indices, not vertex indices. If at the end of * the algorithm (after \p steps steps was done) there are p - * communities, then these are numbered from zero to p-1. + * communities, then these are numbered from zero to p-1. * The first line of the matrix contains the first merge * (which is in reality the last split) of two communities into - * community p, the merge in the second line forms - * community p+1, etc. The matrix should be + * community p, the merge in the second line forms + * community p+1, etc. The matrix should be * initialized before calling and will be resized as needed. * This argument is ignored if it is \c NULL. * \param membership The membership of the vertices after all the diff --git a/src/vendor/cigraph/src/community/leiden.c b/src/vendor/cigraph/src/community/leiden.c index 693e49fbba..803c77d6d4 100644 --- a/src/vendor/cigraph/src/community/leiden.c +++ b/src/vendor/cigraph/src/community/leiden.c @@ -869,15 +869,13 @@ static igraph_error_t igraph_i_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 + * structure. * * * 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). + * from the resolution-limit (see Tragg, Van Dooren & Nesterov). * * * The Leiden algorithm consists of three phases: (1) local moving of nodes, (2) @@ -908,17 +906,33 @@ static igraph_error_t igraph_i_community_leiden( * The objective function being optimized is * * - * 1 / 2m sum_ij (A_ij - gamma n_i n_j)d(s_i, s_j) + * 1 / 2m sum_ij (A_ij - γ n_i n_j) δ(s_i, s_j) * * - * where m is the total edge weight, A_ij is the weight of edge (i, j), gamma is - * the so-called resolution parameter, n_i is the node weight of node i, s_i is - * the cluster of node i and d(x, y) = 1 if and only if x = y and 0 otherwise. - * By setting n_i = k_i, the degree of node i, and dividing gamma by 2m, you - * effectively obtain an expression for modularity. Hence, the standard - * modularity will be optimized when you supply the degrees as \c node_weights - * and by supplying as a resolution parameter 1.0/(2*m), with m the number of - * edges. + * where m is the total edge weight, A_ij is the weight of edge + * (i, j), \c γ is the so-called resolution parameter, n_i + * is the node weight of node \c i, s_i is the cluster of node + * \c i and δ(x, y) = 1 if and only if x = y and 0 + * otherwise. By setting n_i = k_i, the degree of node \c i, and + * dividing \c γ by 2m, we 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/(2m), with \c m the number of edges. + * + * + * References: + * + * + * V. A. Traag, L. Waltman, N. J. van Eck: + * From Louvain to Leiden: guaranteeing well-connected communities. + * Scientific Reports, 9(1), 5233 (2019). + * http://dx.doi.org/10.1038/s41598-019-41695-z + * + * + * V. A. Traag, P. Van Dooren, and Y. Nesterov: + * Narrow scope for resolution-limit-free community detection. + * Phys. Rev. E 84, 016114 (2011). + * https://doi.org/10.1103/PhysRevE.84.016114 * * \param graph The input graph. It must be an undirected graph. * \param edge_weights Numeric vector containing edge weights. If \c NULL, every edge diff --git a/src/vendor/cigraph/src/community/louvain.c b/src/vendor/cigraph/src/community/louvain.c index 9f887f262e..72e3035100 100644 --- a/src/vendor/cigraph/src/community/louvain.c +++ b/src/vendor/cigraph/src/community/louvain.c @@ -28,6 +28,7 @@ #include "igraph_interface.h" #include "igraph_memory.h" #include "igraph_qsort.h" +#include "igraph_random.h" #include "core/interruption.h" @@ -384,6 +385,7 @@ static igraph_error_t igraph_i_community_multilevel_step( q = igraph_i_multilevel_community_modularity(&communities, resolution); /* pass = 1; */ + RNG_BEGIN(); do { /* Pass begin */ igraph_integer_t temp_communities_no = communities.communities_no; @@ -393,6 +395,18 @@ static igraph_error_t igraph_i_community_multilevel_step( /* Save the current membership, it will be restored in case of worse result */ IGRAPH_CHECK(igraph_vector_int_update(&temp_membership, communities.membership)); + /* Apply a random inversion to the node_order permutation vector to help escape + * rare situations of an infinite loop. A full re-shuffling of node_order would + * have a measurable performance impact, hence the single inversion. + * See https://github.com/igraph/igraph/issues/2650 for details. */ + if (vcount > 1) { + igraph_integer_t i1 = RNG_INTEGER(0, vcount-1); + igraph_integer_t i2 = RNG_INTEGER(0, vcount-1); + igraph_integer_t tmp = VECTOR(node_order)[i1]; + VECTOR(node_order)[i1] = VECTOR(node_order)[i2]; + VECTOR(node_order)[i2] = tmp; + } + for (igraph_integer_t i = 0; i < vcount; i++) { /* Exclude vertex from its current community */ igraph_real_t weight_all = 0; @@ -475,6 +489,7 @@ static igraph_error_t igraph_i_community_multilevel_step( IGRAPH_ALLOW_INTERRUPTION(); } while (changed && (q > pass_q)); /* Pass end */ + RNG_END(); if (modularity) { *modularity = q; @@ -520,16 +535,10 @@ static igraph_error_t igraph_i_community_multilevel_step( /** * \ingroup communities * \function igraph_community_multilevel - * \brief Finding community structure by multi-level optimization of modularity. + * \brief Finding community structure by multi-level optimization of modularity (Louvain). * - * This function implements the multi-level modularity optimization - * algorithm for finding community structure, see - * Blondel, V. D., Guillaume, J.-L., Lambiotte, R., & Lefebvre, E. (2008). Fast - * unfolding of communities in large networks. Journal of Statistical Mechanics: - * Theory and Experiment, 10008(10), 6. - * https://doi.org/10.1088/1742-5468/2008/10/P10008 for the details (preprint: - * http://arxiv.org/abs/0803.0476). The algorithm is sometimes known as the - * "Louvain" algorithm. + * This function implements a multi-level modularity optimization algorithm + * for finding community structure, sometimes known as the Louvain algorithm. * * * The algorithm is based on the modularity measure and a hierarchical approach. @@ -542,16 +551,25 @@ static igraph_error_t igraph_i_community_multilevel_step( * the modularity cannot be increased any more in a step. * * - * The resolution parameter \c gamma allows finding communities at different + * The resolution parameter \c γ allows finding communities at different * resolutions. Higher values of the resolution parameter typically result in * more, smaller communities. Lower values typically result in fewer, larger * communities. The original definition of modularity is retrieved when setting - * gamma=1. Note that the returned modularity value is calculated using + * γ=1. Note that the returned modularity value is calculated using * the indicated resolution parameter. See \ref igraph_modularity() for more details. * * * The original version of this function was contributed by Tom Gregorovic. * + * + * Reference: + * + * + * Blondel, V. D., Guillaume, J.-L., Lambiotte, R., & Lefebvre, E.: + * Fast unfolding of communities in large networks. + * Journal of Statistical Mechanics: Theory and Experiment, 10008(10), 6 (2008). + * https://doi.org/10.1088/1742-5468/2008/10/P10008 + * * \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. diff --git a/src/vendor/cigraph/src/community/modularity.c b/src/vendor/cigraph/src/community/modularity.c index 5167bc40ed..953fb24eb3 100644 --- a/src/vendor/cigraph/src/community/modularity.c +++ b/src/vendor/cigraph/src/community/modularity.c @@ -138,9 +138,7 @@ igraph_error_t igraph_modularity(const igraph_t *graph, if (no_of_edges == 0) { /* Special case: the modularity of graphs with no edges is not * well-defined */ - if (modularity) { - *modularity = IGRAPH_NAN; - } + *modularity = IGRAPH_NAN; return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/community/optimal_modularity.c b/src/vendor/cigraph/src/community/optimal_modularity.c index 53d9506a83..0a66b5ed33 100644 --- a/src/vendor/cigraph/src/community/optimal_modularity.c +++ b/src/vendor/cigraph/src/community/optimal_modularity.c @@ -32,12 +32,6 @@ #include "internal/glpk_support.h" #include "math/safe_intop.h" -#include "config.h" - -#ifdef HAVE_GLPK - #include -#endif - #include /** @@ -124,13 +118,27 @@ igraph_error_t igraph_community_optimal_modularity(const igraph_t *graph, /* Avoid problems with the null graph */ if (no_of_nodes < 2) { + /* Cater for the case when membership was not given, but modularity was requested. */ + igraph_vector_int_t imembership, *pmembership; if (membership) { - IGRAPH_CHECK(igraph_vector_int_resize(membership, no_of_nodes)); - igraph_vector_int_null(membership); + pmembership = membership; + } else { + IGRAPH_VECTOR_INT_INIT_FINALLY(&imembership, no_of_nodes); + pmembership = &imembership; } + + IGRAPH_CHECK(igraph_vector_int_resize(pmembership, no_of_nodes)); + igraph_vector_int_null(pmembership); + if (modularity) { - IGRAPH_CHECK(igraph_modularity(graph, membership, 0, 1, igraph_is_directed(graph), modularity)); + IGRAPH_CHECK(igraph_modularity(graph, pmembership, NULL, 1, igraph_is_directed(graph), modularity)); } + + if (! membership) { + igraph_vector_int_destroy(&imembership); + IGRAPH_FINALLY_CLEAN(1); + } + return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/community/spinglass/clustertool.cpp b/src/vendor/cigraph/src/community/spinglass/clustertool.cpp index 06b1c779ed..118da4fad0 100644 --- a/src/vendor/cigraph/src/community/spinglass/clustertool.cpp +++ b/src/vendor/cigraph/src/community/spinglass/clustertool.cpp @@ -108,9 +108,8 @@ static igraph_error_t igraph_i_community_spinglass_negative( * implementation. * \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. + * gereralized modularity, taking into account the resolution parameter + * \p gamma. See \ref igraph_modularity() for details. * \param temperature Pointer to a real number, if not \c NULL then * the temperature at the end of the algorithm will be stored * here. @@ -159,7 +158,7 @@ static igraph_error_t igraph_i_community_spinglass_negative( * weights, using the number of spins as the number of colors. * \return Error code. * - * \sa igraph_community_spinglass_single() for calculating the community + * \sa \ref igraph_community_spinglass_single() for calculating the community * of a single vertex. * * Time complexity: TODO. diff --git a/src/vendor/cigraph/src/community/voronoi.c b/src/vendor/cigraph/src/community/voronoi.c index aeaeac8de7..fc3fabeefb 100644 --- a/src/vendor/cigraph/src/community/voronoi.c +++ b/src/vendor/cigraph/src/community/voronoi.c @@ -170,7 +170,7 @@ static igraph_error_t choose_generators( /* ord[i] is the index of the ith largest element of local_rel_dens */ IGRAPH_VECTOR_INT_INIT_FINALLY(&ord, 0); - IGRAPH_CHECK(igraph_vector_qsort_ind(local_rel_dens, &ord, IGRAPH_DESCENDING)); + IGRAPH_CHECK(igraph_vector_sort_ind(local_rel_dens, &ord, IGRAPH_DESCENDING)); /* If excluded[v] is true, then v is closer to some already chosen generator than r */ IGRAPH_BITSET_INIT_FINALLY(&excluded, no_of_nodes); @@ -635,7 +635,7 @@ igraph_error_t igraph_community_voronoi( IGRAPH_CHECK(choose_generators(graph, pgenerators, NULL, &local_rel_dens, &lengths2, mode, r)); IGRAPH_CHECK(igraph_voronoi(graph, membership, NULL, pgenerators, &lengths2, mode, IGRAPH_VORONOI_RANDOM)); if (modularity) { - IGRAPH_CHECK(igraph_modularity(graph, membership, weights, 1, + IGRAPH_CHECK(igraph_modularity(graph, pmembership, weights, 1, mode == IGRAPH_ALL ? IGRAPH_UNDIRECTED : IGRAPH_DIRECTED, modularity)); } } diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap.cpp b/src/vendor/cigraph/src/community/walktrap/walktrap.cpp index 1fb9d09ef0..4efadc9d80 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap.cpp +++ b/src/vendor/cigraph/src/community/walktrap/walktrap.cpp @@ -109,8 +109,9 @@ using namespace igraph::walktrap; * 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. + * vertices in the graph) numbered from zero to n - 1. + * The first merge creates cluster \c n, the second cluster + * n + 1, etc. * \param modularity Pointer to a vector. If not \c NULL then the * modularity score of the current clustering is stored here after * each merge operation. diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp index 7844b7c01f..8b363dda16 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.cpp @@ -54,7 +54,7 @@ // see readme.txt for more details #include "walktrap_communities.h" -#include "config.h" +#include "config.h" /* IGRAPH_THREAD_LOCAL */ #include #include diff --git a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h index 484079f706..6017c3a20f 100644 --- a/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h +++ b/src/vendor/cigraph/src/community/walktrap/walktrap_communities.h @@ -59,7 +59,7 @@ #include "walktrap_graph.h" #include "walktrap_heap.h" -#include "config.h" +#include "config.h" /* IGRAPH_THREAD_LOCAL */ namespace igraph { diff --git a/src/vendor/cigraph/src/config.h.in b/src/vendor/cigraph/src/config.h.in index 28cf4e2f43..ca06c90782 100644 --- a/src/vendor/cigraph/src/config.h.in +++ b/src/vendor/cigraph/src/config.h.in @@ -1,8 +1,6 @@ #ifndef IGRAPH_PRIVATE_CONFIG_H #define IGRAPH_PRIVATE_CONFIG_H -#include "igraph_config.h" - #cmakedefine HAVE_STRCASECMP 1 #cmakedefine HAVE_STRNCASECMP 1 #cmakedefine HAVE__STRICMP 1 diff --git a/src/vendor/cigraph/src/connectivity/components.c b/src/vendor/cigraph/src/connectivity/components.c index 87832ec032..74bde23424 100644 --- a/src/vendor/cigraph/src/connectivity/components.c +++ b/src/vendor/cigraph/src/connectivity/components.c @@ -84,7 +84,7 @@ igraph_error_t igraph_clusters(const igraph_t *graph, igraph_vector_int_t *membe * \cli IGRAPH_WEAK * Compute weakly connected components, i.e. ignore edge directions. * \cli IGRAPH_STRONG - * Compute strongly connnected components, i.e. considr edge directions. + * Compute strongly connnected components, i.e. consider edge directions. * \endclist * This parameter is ignored for undirected graphs. * \return Error code. @@ -621,11 +621,11 @@ static igraph_error_t igraph_i_decompose_strong(const igraph_t *graph, * \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. + * 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. + * vector. For example, supplying 2 here ignored isolated vertices. * \return Error code, \c IGRAPH_ENOMEM if there is not enough memory * to perform the operation. * diff --git a/src/vendor/cigraph/src/core/bitset.c b/src/vendor/cigraph/src/core/bitset.c index 2a94f07b0a..3b98bc8ca7 100644 --- a/src/vendor/cigraph/src/core/bitset.c +++ b/src/vendor/cigraph/src/core/bitset.c @@ -1,5 +1,3 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* IGraph library. Copyright (C) 2024 The igraph development team @@ -109,14 +107,20 @@ igraph_integer_t igraph_i_clz64(igraph_uint_t x) { * * The elements in an \type igraph_bitset_t object and its variants are * indexed from zero, we follow the usual C convention here. Bitsets are indexed - * from right to left, meaning index 0 is the least significant bit and index n-1 - * is the most significant bit. + * from right to left, meaning index 0 is the least significant bit and index + * n - 1 is the most significant bit. * * The elements of a bitset always occupy a single block of * memory, the starting address of this memory block can be queried * with the \ref VECTOR() macro. This way, bitset objects can be used * with standard mathematical libraries, like the GNU Scientific * Library. + * + * Note that while the interface of bitset functions is similar to + * igraph's vector functions, there is one major difference: bitset functions + * such as \ref igraph_bitset_and() do not verify that that sizes of input + * parameters are compatible, and do not automatically resize the output + * parameter. Doing so is the responsibility of the user. */ /** @@ -184,7 +188,6 @@ igraph_error_t igraph_bitset_init(igraph_bitset_t *bitset, igraph_integer_t size * * \experimental * - * * All bitsets initialized by \ref igraph_bitset_init() should be properly * destroyed by this function. A destroyed bitset needs to be * reinitialized by \ref igraph_bitset_init() or @@ -209,10 +212,9 @@ void igraph_bitset_destroy(igraph_bitset_t *bitset) { * * \experimental * - * - * * The contents of the existing bitset object will be copied to * the new one. + * * \param dest Pointer to a not yet initialized bitset object. * \param src The original bitset object to copy. * \return Error code: @@ -234,6 +236,37 @@ igraph_error_t igraph_bitset_init_copy(igraph_bitset_t *dest, const igraph_bitse return IGRAPH_SUCCESS; } +/** + * \ingroup bitset + * \function igraph_bitset_update + * \brief Update a bitset from another one. + * + * \experimental + * + * The size and contents of \p dest will be identical to that of \p src. + * + * \param dest Pointer to an initialized bitset object. This will be updated. + * \param src The bitset to update from. + * \return Error code: + * \c IGRAPH_ENOMEM if there is not enough memory. + * + * Time complexity: operating system dependent, usually + * O(n/w), + * n is the size of the bitset, + * w is the word size of the machine (32 or 64). + */ + +igraph_error_t igraph_bitset_update(igraph_bitset_t *dest, const igraph_bitset_t *src) { + IGRAPH_ASSERT(src != NULL); + IGRAPH_ASSERT(src->stor_begin != NULL); + IGRAPH_CHECK(igraph_bitset_reserve(dest, src->size)); + dest->size = src->size; + for (igraph_integer_t i = 0; i < IGRAPH_BIT_NSLOTS(dest->size); ++i) { + VECTOR(*dest)[i] = VECTOR(*src)[i]; + } + return IGRAPH_SUCCESS; +} + /** * \ingroup bitset * \function igraph_bitset_capacity @@ -282,7 +315,6 @@ igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset) { * * \experimental * - * * \a igraph bitsets are flexible, they can grow and * shrink. Growing * however occasionally needs the data in the bitset to be copied. @@ -295,6 +327,7 @@ igraph_integer_t igraph_bitset_size(const igraph_bitset_t *bitset) { * reserve space for 100 elements and the size of your * bitset was (and still is) 60, then you can surely add additional 40 * elements to your bitset before it will be copied. + * * \param bitset The bitset object. * \param capacity The new \em allocated size of the bitset. * \return Error code: @@ -336,7 +369,6 @@ igraph_error_t igraph_bitset_reserve(igraph_bitset_t *bitset, igraph_integer_t c * * \experimental * - * * Note that this function does not free any memory, just sets the * size of the bitset to the given one. It may, on the other hand, * allocate more memory if the new size is larger than the previous @@ -661,8 +693,8 @@ igraph_bool_t igraph_bitset_is_any_one(const igraph_bitset_t *bitset) { * must do so if necessary. * * \param dest The bitset object where the result is stored - * \param src1 A bitset - * \param src2 A bitset + * \param src1 A bitset. Must have have same size as \p dest. + * \param src2 A bitset. Must have have same size as \p dest. * * Time complexity: O(n/w). */ @@ -689,8 +721,8 @@ void igraph_bitset_or(igraph_bitset_t *dest, * must do so if necessary. * * \param dest The bitset object where the result is stored - * \param src1 A bitset - * \param src2 A bitset + * \param src1 A bitset. Must have have same size as \p dest. + * \param src2 A bitset. Must have have same size as \p dest. * * Time complexity: O(n/w). */ @@ -716,8 +748,8 @@ void igraph_bitset_and(igraph_bitset_t *dest, const igraph_bitset_t *src1, const * must do so if necessary. * * \param dest The bitset object where the result is stored - * \param src1 A bitset - * \param src2 A bitset + * \param src1 A bitset. Must have have same size as \p dest. + * \param src2 A bitset. Must have have same size as \p dest. * * Time complexity: O(n/w). */ @@ -743,7 +775,7 @@ void igraph_bitset_xor(igraph_bitset_t *dest, * sizes of the bitsets passed to it, the caller must do so if necessary. * * \param dest The bitset object where the result is stored - * \param src A bitset + * \param src A bitset. Must have have same size as \p dest. * * Time complexity: O(n/w). */ @@ -766,7 +798,7 @@ void igraph_bitset_not(igraph_bitset_t *dest, const igraph_bitset_t *src) { * \param bitset The bitset object to modify. * \param value The value to set for all bits. * -* \sa \ref igraph_bitset_null() + * \sa \ref igraph_bitset_null() * * Time complexity: O(n/w). */ diff --git a/src/vendor/cigraph/src/core/bitset_list.c b/src/vendor/cigraph/src/core/bitset_list.c index a2f783aead..3fdd36b0f1 100644 --- a/src/vendor/cigraph/src/core/bitset_list.c +++ b/src/vendor/cigraph/src/core/bitset_list.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* IGraph library. - Copyright (C) 2022 The igraph development team - 334 Harvard street, Cambridge, MA 02139 USA + Copyright (C) 2024 The igraph development 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 @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_bitset_list.h" diff --git a/src/vendor/cigraph/src/core/error.c b/src/vendor/cigraph/src/core/error.c index 8436c7f56a..e064eb42bd 100644 --- a/src/vendor/cigraph/src/core/error.c +++ b/src/vendor/cigraph/src/core/error.c @@ -21,10 +21,11 @@ */ -#include "config.h" #include "igraph_error.h" #include "igraph_types.h" +#include "config.h" /* IGRAPH_THREAD_LOCAL */ + #include #include #include diff --git a/src/vendor/cigraph/src/core/interruption.c b/src/vendor/cigraph/src/core/interruption.c index 794220389a..08aebf77d8 100644 --- a/src/vendor/cigraph/src/core/interruption.c +++ b/src/vendor/cigraph/src/core/interruption.c @@ -22,7 +22,8 @@ */ #include "igraph_interrupt.h" -#include "config.h" + +#include "config.h" /* IGRAPH_THREAD_LOCAL */ IGRAPH_THREAD_LOCAL igraph_interruption_handler_t *igraph_i_interruption_handler = 0; diff --git a/src/vendor/cigraph/src/core/interruption.h b/src/vendor/cigraph/src/core/interruption.h index 98cbafbf3c..a7866226d8 100644 --- a/src/vendor/cigraph/src/core/interruption.h +++ b/src/vendor/cigraph/src/core/interruption.h @@ -26,7 +26,8 @@ #include "igraph_decls.h" #include "igraph_interrupt.h" -#include "config.h" + +#include "config.h" /* IGRAPH_THREAD_LOCAL */ __BEGIN_DECLS diff --git a/src/vendor/cigraph/src/core/memory.c b/src/vendor/cigraph/src/core/memory.c index 490db99a7a..b3e244c059 100644 --- a/src/vendor/cigraph/src/core/memory.c +++ b/src/vendor/cigraph/src/core/memory.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* IGraph library. - Copyright (C) 2003-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + Copyright (C) 2003-2024 The igraph development 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 @@ -15,41 +13,42 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_memory.h" /** - * \section about-alloc-funcs About allocation functions + * \section about_alloc_funcs About allocation functions * - * Some igraph functions return a pointer vector (igraph_vector_ptr_t) + * + * Some igraph functions return a pointer vector (\type 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 when the user does not need them any more. \c igraph_vector_ptr_t + * manually when the user does not need them any more. \type igraph_vector_ptr_t * has functions to deallocate the contained pointers on its own, but in this * case it has to be ensured that these pointers are allocated by a function - * that corresponding to the deallocator function that igraph uses. + * that corresponds to the deallocator function that igraph uses. + * * - * + * * To this end, igraph exports the memory allocation functions that are used * internally so the user of the library can ensure that the proper functions * are used when pointers are moved between the code written by the user and * the code of the igraph library. + * * - * + * * Additionally, the memory allocator functions used by igraph work around the - * quirk of classical \c malloc(), \c realloc() and \c calloc() implementations + * quirks of classical \c malloc(), \c realloc() and \c calloc() implementations * where the behaviour of allocating zero bytes is undefined. igraph allocator * functions will always allocate at least one byte. + * */ /** * \function igraph_free - * \brief Deallocate memory that was allocated by igraph functions. + * \brief Deallocates memory that was allocated by igraph functions. * * This function exposes the \c free() function used internally by igraph. * @@ -67,7 +66,7 @@ void igraph_free(void *ptr) { /** * \function igraph_calloc - * \brief Allocate memory that can be safely deallocated by igraph functions. + * \brief Allocates memory that can be safely deallocated by igraph functions. * * This function behaves like \c calloc(), but it ensures that at least one * byte is allocated even when the caller asks for zero bytes. @@ -87,7 +86,7 @@ void *igraph_calloc(size_t count, size_t size) { /** * \function igraph_malloc - * \brief Allocate memory that can be safely deallocated by igraph functions. + * \brief Allocates memory that can be safely deallocated by igraph functions. * * This function behaves like \c malloc(), but it ensures that at least one * byte is allocated even when the caller asks for zero bytes. @@ -119,6 +118,6 @@ void *igraph_malloc(size_t size) { * \sa \ref igraph_free(), \ref igraph_malloc() */ -void *igraph_realloc(void* ptr, size_t size) { - return (void*) IGRAPH_REALLOC(ptr, size, char); +void *igraph_realloc(void *ptr, size_t size) { + return (void *) IGRAPH_REALLOC(ptr, size, char); } diff --git a/src/vendor/cigraph/src/core/progress.c b/src/vendor/cigraph/src/core/progress.c index 8cf35a8016..b5021e05f7 100644 --- a/src/vendor/cigraph/src/core/progress.c +++ b/src/vendor/cigraph/src/core/progress.c @@ -23,7 +23,7 @@ #include "igraph_progress.h" -#include "config.h" +#include "config.h" /* IGRAPH_THREAD_LOCAL */ static IGRAPH_THREAD_LOCAL igraph_progress_handler_t *igraph_i_progress_handler = 0; static IGRAPH_THREAD_LOCAL char igraph_i_progressmsg_buffer[1000]; diff --git a/src/vendor/cigraph/src/core/set.c b/src/vendor/cigraph/src/core/set.c index 5ee8667a06..bf4fe729c5 100644 --- a/src/vendor/cigraph/src/core/set.c +++ b/src/vendor/cigraph/src/core/set.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ /* IGraph library. - Copyright (C) 2006-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + Copyright (C) 2006-2024 The igraph development 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 @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_memory.h" @@ -71,7 +66,7 @@ igraph_error_t igraph_set_init(igraph_set_t *set, igraph_integer_t capacity) { * * Time complexity: operating system dependent. */ -void igraph_set_destroy(igraph_set_t* set) { +void igraph_set_destroy(igraph_set_t *set) { IGRAPH_ASSERT(set != NULL); if (set->stor_begin != NULL) { IGRAPH_FREE(set->stor_begin); /* sets to NULL */ @@ -93,7 +88,7 @@ void igraph_set_destroy(igraph_set_t* set) { * * Time complexity: O(1) */ -igraph_bool_t igraph_set_inited(igraph_set_t* set) { +igraph_bool_t igraph_set_inited(igraph_set_t *set) { return (set->stor_begin != NULL); } @@ -108,7 +103,7 @@ igraph_bool_t igraph_set_inited(igraph_set_t* set) { * Time complexity: operating system dependent, should be around * O(n), n is the new allocated size of the set. */ -igraph_error_t igraph_set_reserve(igraph_set_t* set, igraph_integer_t capacity) { +igraph_error_t igraph_set_reserve(igraph_set_t *set, igraph_integer_t capacity) { igraph_integer_t actual_size = igraph_set_size(set); igraph_integer_t *tmp; IGRAPH_ASSERT(set != NULL); @@ -137,7 +132,7 @@ igraph_error_t igraph_set_reserve(igraph_set_t* set, igraph_integer_t capacity) * * Time complexity: O(1). */ -igraph_bool_t igraph_set_empty(const igraph_set_t* set) { +igraph_bool_t igraph_set_empty(const igraph_set_t *set) { IGRAPH_ASSERT(set != NULL); IGRAPH_ASSERT(set->stor_begin != NULL); return set->stor_begin == set->end; @@ -148,16 +143,16 @@ igraph_bool_t igraph_set_empty(const igraph_set_t* set) { * \function igraph_set_clear * \brief Removes all elements from the set. * - * * 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 set The set object. * * Time complexity: O(1). */ -void igraph_set_clear(igraph_set_t* set) { +void igraph_set_clear(igraph_set_t *set) { IGRAPH_ASSERT(set != NULL); IGRAPH_ASSERT(set->stor_begin != NULL); set->end = set->stor_begin; @@ -177,7 +172,7 @@ void igraph_set_clear(igraph_set_t* set) { * Time complexity: O(1). */ -igraph_integer_t igraph_set_size(const igraph_set_t* set) { +igraph_integer_t igraph_set_size(const igraph_set_t *set) { IGRAPH_ASSERT(set != NULL); IGRAPH_ASSERT(set->stor_begin != NULL); return set->end - set->stor_begin; @@ -196,7 +191,7 @@ igraph_integer_t igraph_set_size(const igraph_set_t* set) { * * Time complexity: O(log(n)), n is the number of elements in \p set. */ -igraph_error_t igraph_set_add(igraph_set_t* set, igraph_integer_t e) { +igraph_error_t igraph_set_add(igraph_set_t *set, igraph_integer_t e) { igraph_integer_t left, right, middle; igraph_integer_t size; IGRAPH_ASSERT(set != NULL); @@ -262,7 +257,7 @@ igraph_error_t igraph_set_add(igraph_set_t* set, igraph_integer_t e) { * * Time complexity: O(log(n)), n is the number of elements in \p set. */ -igraph_bool_t igraph_set_contains(const igraph_set_t* set, igraph_integer_t e) { +igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_integer_t e) { igraph_integer_t left, right, middle; IGRAPH_ASSERT(set != NULL); @@ -299,7 +294,7 @@ igraph_bool_t igraph_set_contains(const igraph_set_t* set, igraph_integer_t e) { * * \param set The set object. * \param state Internal state of the iteration. - * This should be a pointer to an \c igraph_integer_t variable + * This should be a pointer to a \type igraph_integer_t variable * which must be zero for the first invocation. * The object must not be adjusted and its value should * not be used for anything during the iteration. diff --git a/src/vendor/cigraph/src/core/set.h b/src/vendor/cigraph/src/core/set.h index 8f5b3e3225..cd6c8540d1 100644 --- a/src/vendor/cigraph/src/core/set.h +++ b/src/vendor/cigraph/src/core/set.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* IGraph library. - Copyright (C) 2009-2020 The igraph development team + Copyright (C) 2009-2024 The igraph development 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 @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_CORE_SET_H @@ -49,17 +45,18 @@ typedef struct s_set { do { IGRAPH_CHECK(igraph_set_init(v, size)); \ IGRAPH_FINALLY(igraph_set_destroy, v); } while (0) -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_init(igraph_set_t* set, igraph_integer_t size); -IGRAPH_PRIVATE_EXPORT void igraph_set_destroy(igraph_set_t* set); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_inited(igraph_set_t* set); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_reserve(igraph_set_t* set, igraph_integer_t size); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_empty(const igraph_set_t* set); -IGRAPH_PRIVATE_EXPORT void igraph_set_clear(igraph_set_t* set); -IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_set_size(const igraph_set_t* set); -IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_add(igraph_set_t* v, igraph_integer_t e); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_init(igraph_set_t *set, igraph_integer_t capacity); +IGRAPH_PRIVATE_EXPORT void igraph_set_destroy(igraph_set_t *set); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_inited(igraph_set_t *set); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_reserve(igraph_set_t *set, igraph_integer_t capacity); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_empty(const igraph_set_t *set); +IGRAPH_PRIVATE_EXPORT void igraph_set_clear(igraph_set_t *set); +IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_integer_t igraph_set_size(const igraph_set_t *set); +IGRAPH_PRIVATE_EXPORT igraph_error_t igraph_set_add(igraph_set_t *set, igraph_integer_t e); IGRAPH_PRIVATE_EXPORT IGRAPH_FUNCATTR_PURE igraph_bool_t igraph_set_contains(const igraph_set_t *set, igraph_integer_t e); -IGRAPH_PRIVATE_EXPORT igraph_bool_t igraph_set_iterate(const igraph_set_t *set, igraph_integer_t* state, - igraph_integer_t* element); +IGRAPH_PRIVATE_EXPORT igraph_bool_t igraph_set_iterate(const igraph_set_t *set, + igraph_integer_t *state, + igraph_integer_t *element); __END_DECLS diff --git a/src/vendor/cigraph/src/core/statusbar.c b/src/vendor/cigraph/src/core/statusbar.c index 48e47b9492..503bb34e44 100644 --- a/src/vendor/cigraph/src/core/statusbar.c +++ b/src/vendor/cigraph/src/core/statusbar.c @@ -24,7 +24,7 @@ #include "igraph_statusbar.h" #include "igraph_error.h" -#include "config.h" +#include "config.h" /* IGRAPH_THREAD_LOCAL */ #include #include diff --git a/src/vendor/cigraph/src/core/strvector.c b/src/vendor/cigraph/src/core/strvector.c index eb4bc2ea78..62927ed082 100644 --- a/src/vendor/cigraph/src/core/strvector.c +++ b/src/vendor/cigraph/src/core/strvector.c @@ -697,3 +697,21 @@ igraph_error_t igraph_strvector_index(const igraph_strvector_t *sv, return IGRAPH_SUCCESS; } + +/** + * \function igraph_strvector_swap_elements + * \brief Swap two elements in a string vector. + * + * Note that currently no range checking is performed. + * + * \param sv The string vector. + * \param i Index of the first element. + * \param j Index of the second element (may be the same as the first one). + * + * Time complexity: O(1). + */ +void igraph_strvector_swap_elements(igraph_strvector_t *sv, igraph_integer_t i, igraph_integer_t j) { + char *tmp = sv->stor_begin[i]; + sv->stor_begin[i] = sv->stor_begin[j]; + sv->stor_begin[j] = tmp; +} diff --git a/src/vendor/cigraph/src/core/typed_list.pmt b/src/vendor/cigraph/src/core/typed_list.pmt index 2ec3a41a0c..979af44deb 100644 --- a/src/vendor/cigraph/src/core/typed_list.pmt +++ b/src/vendor/cigraph/src/core/typed_list.pmt @@ -71,13 +71,13 @@ #endif #endif -static igraph_error_t INTERNAL_FUNCTION(init_item)(const TYPE* list, ITEM_TYPE* item); -static igraph_error_t INTERNAL_FUNCTION(copy_item)(ITEM_TYPE* dest, const ITEM_TYPE* source); -static void INTERNAL_FUNCTION(destroy_item)(ITEM_TYPE* item); +static igraph_error_t INTERNAL_FUNCTION(init_item)(const TYPE *list, ITEM_TYPE *item); +static igraph_error_t INTERNAL_FUNCTION(copy_item)(ITEM_TYPE *dest, const ITEM_TYPE *source); +static void INTERNAL_FUNCTION(destroy_item)(ITEM_TYPE *item); -static igraph_error_t INTERNAL_FUNCTION(init_slice)(const TYPE* list, ITEM_TYPE* start, ITEM_TYPE* end); -static void INTERNAL_FUNCTION(destroy_slice)(const TYPE* list, ITEM_TYPE* start, ITEM_TYPE* end); -static igraph_error_t INTERNAL_FUNCTION(expand_if_full)(TYPE* list); +static igraph_error_t INTERNAL_FUNCTION(init_slice)(const TYPE *list, ITEM_TYPE *start, ITEM_TYPE *end); +static void INTERNAL_FUNCTION(destroy_slice)(const TYPE *list, ITEM_TYPE *start, ITEM_TYPE *end); +static igraph_error_t INTERNAL_FUNCTION(expand_if_full)(TYPE *list); static int INTERNAL_FUNCTION(sort_ind_cmp)(void *thunk, const void *p1, const void *p2); /** @@ -105,7 +105,7 @@ static int INTERNAL_FUNCTION(sort_ind_cmp)(void *thunk, const void *p1, const vo * n is the number of elements. */ -igraph_error_t FUNCTION(init)(TYPE* v, igraph_integer_t size) { +igraph_error_t FUNCTION(init)(TYPE *v, igraph_integer_t size) { igraph_integer_t alloc_size = size > 0 ? size : 1; IGRAPH_ASSERT(size >= 0); v->stor_begin = IGRAPH_CALLOC(alloc_size, ITEM_TYPE); @@ -140,7 +140,7 @@ igraph_error_t FUNCTION(init)(TYPE* v, igraph_integer_t size) { * Time complexity: operating system dependent. */ -void FUNCTION(destroy)(TYPE* v) { +void FUNCTION(destroy)(TYPE *v) { IGRAPH_ASSERT(v != 0); if (v->stor_begin != 0) { @@ -167,7 +167,7 @@ void FUNCTION(destroy)(TYPE* v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(capacity)(const TYPE* v) { +igraph_integer_t FUNCTION(capacity)(const TYPE *v) { return v->stor_end - v->stor_begin; } @@ -197,7 +197,7 @@ igraph_integer_t FUNCTION(capacity)(const TYPE* v) { * O(n), n is the new allocated size of the list. */ -igraph_error_t FUNCTION(reserve)(TYPE* v, igraph_integer_t capacity) { +igraph_error_t FUNCTION(reserve)(TYPE *v, igraph_integer_t capacity) { igraph_integer_t current_capacity; ITEM_TYPE *tmp; @@ -232,7 +232,7 @@ igraph_error_t FUNCTION(reserve)(TYPE* v, igraph_integer_t capacity) { * Time complexity: O(1). */ -igraph_bool_t FUNCTION(empty)(const TYPE* v) { +igraph_bool_t FUNCTION(empty)(const TYPE *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->stor_begin == v->end; @@ -241,7 +241,9 @@ igraph_bool_t FUNCTION(empty)(const TYPE* v) { /** * \ingroup vector_list * \function igraph_vector_list_size - * \brief Returns the size (=length) of the vector. + * \brief The size of the vector list. + * + * Returns the number of vectors stored in the list. * * \param v The list object * \return The size of the list. @@ -249,7 +251,7 @@ igraph_bool_t FUNCTION(empty)(const TYPE* v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(size)(const TYPE* v) { +igraph_integer_t FUNCTION(size)(const TYPE *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->end - v->stor_begin; @@ -258,7 +260,7 @@ igraph_integer_t FUNCTION(size)(const TYPE* v) { /** * \ingroup vector_list * \function igraph_vector_list_resize - * \brief Resize the list of vectors. + * \brief Resizes the list of vectors. * * * Note that this function does not free any memory, just sets the @@ -286,7 +288,7 @@ igraph_integer_t FUNCTION(size)(const TYPE* v) { * size is larger. In the latter case it is usually around O(n), where n is the * new size of the vector. */ -igraph_error_t FUNCTION(resize)(TYPE* v, igraph_integer_t new_size) { +igraph_error_t FUNCTION(resize)(TYPE *v, igraph_integer_t new_size) { igraph_integer_t old_size; IGRAPH_ASSERT(v != NULL); @@ -312,7 +314,6 @@ igraph_error_t FUNCTION(resize)(TYPE* v, igraph_integer_t new_size) { * \function igraph_vector_list_clear * \brief Removes all elements from a list of vectors. * - * * This function sets the size of the list to zero, and it also destroys all * the vectors that were placed in the list before clearing it. * @@ -320,7 +321,7 @@ igraph_error_t FUNCTION(resize)(TYPE* v, igraph_integer_t new_size) { * * Time complexity: O(n), n is the number of items being deleted. */ -void FUNCTION(clear)(TYPE* v) { +void FUNCTION(clear)(TYPE *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); INTERNAL_FUNCTION(destroy_slice)(v, v->stor_begin, v->end); @@ -330,7 +331,8 @@ void FUNCTION(clear)(TYPE* v) { /** * \ingroup vector_list * \function igraph_vector_list_get_ptr - * \brief Retrieve the address of a vector in the vector list. + * \brief The address of a vector in the vector list. + * * \param v The list object. * \param pos The position of the vector in the list. The position of the first * vector is zero. @@ -339,7 +341,7 @@ void FUNCTION(clear)(TYPE* v) { * * Time complexity: O(1). */ -ITEM_TYPE* FUNCTION(get_ptr)(const TYPE* v, igraph_integer_t pos) { +ITEM_TYPE *FUNCTION(get_ptr)(const TYPE *v, igraph_integer_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->stor_begin + pos; @@ -364,7 +366,7 @@ ITEM_TYPE* FUNCTION(get_ptr)(const TYPE* v, igraph_integer_t pos) { * * Time complexity: O(1). */ -void FUNCTION(set)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e) { +void FUNCTION(set)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { INTERNAL_FUNCTION(destroy_item)(v->stor_begin + pos); v->stor_begin[pos] = *e; } @@ -389,7 +391,7 @@ void FUNCTION(set)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e) { * * Time complexity: O(1). */ -void FUNCTION(replace)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e) { +void FUNCTION(replace)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { ITEM_TYPE old_value = *(FUNCTION(get_ptr)(v, pos)); v->stor_begin[pos] = *e; *e = old_value; @@ -421,6 +423,7 @@ igraph_error_t FUNCTION(swap)(TYPE *v1, TYPE *v2) { * \brief Swap two elements in a vector list. * * Note that currently no range checking is performed. + * * \param v The input list. * \param i Index of the first element. * \param j Index of the second element (may be the same as the @@ -440,14 +443,15 @@ igraph_error_t FUNCTION(swap_elements)(TYPE *v1, igraph_integer_t i, igraph_inte /** * \ingroup vector_list * \function igraph_vector_list_tail_ptr - * \brief Retrieve the address of the last vector in the vector list. + * \brief The address of the last vector in the vector list. + * * \param v The list object. * \return A pointer to the last vector in the list, or \c NULL if the list * is empty. * * Time complexity: O(1). */ -ITEM_TYPE* FUNCTION(tail_ptr)(const TYPE *v) { +ITEM_TYPE *FUNCTION(tail_ptr)(const TYPE *v) { igraph_integer_t size = FUNCTION(size)(v); return size > 0 ? FUNCTION(get_ptr)(v, size - 1) : 0; } @@ -455,9 +459,8 @@ ITEM_TYPE* FUNCTION(tail_ptr)(const TYPE *v) { /** * \ingroup vector_list * \function igraph_vector_list_discard - * \brief Discard the item at the given index in the vector list. + * \brief Discards the item at the given index in the vector list. * - * * This function removes the vector at the given index from the list, and * moves all subsequent items in the list by one slot to the left to fill * the gap. The vector that was removed from the list is destroyed automatically. @@ -470,7 +473,7 @@ ITEM_TYPE* FUNCTION(tail_ptr)(const TYPE *v) { * * Time complexity: O(n), where n is the number of items in the list. */ -void FUNCTION(discard)(TYPE* v, igraph_integer_t index) { +void FUNCTION(discard)(TYPE *v, igraph_integer_t index) { igraph_integer_t size = FUNCTION(size)(v); if (size > 0) { @@ -483,16 +486,15 @@ void FUNCTION(discard)(TYPE* v, igraph_integer_t index) { /** * \ingroup vector_list * \function igraph_vector_list_discard_back - * \brief Discard the last item in the vector list. + * \brief Discards the last item in the vector list. * - * * This function removes the last vector from the list and destroys it. * * \param v The list object. * * Time complexity: O(1). */ -void FUNCTION(discard_back)(TYPE* v) { +void FUNCTION(discard_back)(TYPE *v) { igraph_integer_t size = FUNCTION(size)(v); if (size > 0) { INTERNAL_FUNCTION(destroy_item)(v->end - 1); @@ -503,9 +505,8 @@ void FUNCTION(discard_back)(TYPE* v) { /** * \ingroup vector_list * \function igraph_vector_list_discard_fast - * \brief Discard the item at the given index in the vector list and move the last item to its place. + * \brief Discards the item at the given index in the vector list and moves the last item to its place. * - * * This function removes the vector at the given index from the list, and * moves the last item in the list to \p index to fill the gap. The vector that * was removed from the list is destroyed automatically. @@ -518,7 +519,7 @@ void FUNCTION(discard_back)(TYPE* v) { * * Time complexity: O(1). */ -void FUNCTION(discard_fast)(TYPE* v, igraph_integer_t index) { +void FUNCTION(discard_fast)(TYPE *v, igraph_integer_t index) { igraph_integer_t size = FUNCTION(size)(v); if (size > 0) { @@ -531,9 +532,8 @@ void FUNCTION(discard_fast)(TYPE* v, igraph_integer_t index) { /** * \ingroup vector_list * \function igraph_vector_list_push_back - * \brief Append an existing vector to the list, transferring ownership. + * \brief Appends an existing vector to the list, transferring ownership. * - * * This function resizes the list to be one element longer, and sets the very last * element in the list to the specified vector \p e . The list takes ownership * of the vector so the user is not responsible for freeing \p e any more; @@ -554,7 +554,7 @@ void FUNCTION(discard_fast)(TYPE* v, igraph_integer_t index) { * as the vector's current length. (We assume here that the time * complexity of memory allocation is at most linear). */ -igraph_error_t FUNCTION(push_back)(TYPE* v, ITEM_TYPE* e) { +igraph_error_t FUNCTION(push_back)(TYPE *v, ITEM_TYPE *e) { IGRAPH_CHECK(INTERNAL_FUNCTION(expand_if_full)(v)); *(v->end) = *e; v->end += 1; @@ -564,9 +564,8 @@ igraph_error_t FUNCTION(push_back)(TYPE* v, ITEM_TYPE* e) { /** * \ingroup vector_list * \function igraph_vector_list_push_back_copy - * \brief Append the copy of a vector to the list. + * \brief Appends the copy of a vector to the list. * - * * This function resizes the list to be one element longer, and copies the * specified vector given as an argument to the last element. The newly added * element is owned by the list, but the ownership of the original vector is @@ -580,7 +579,7 @@ igraph_error_t FUNCTION(push_back)(TYPE* v, ITEM_TYPE* e) { * Time complexity: same as \ref igraph_vector_list_push_back() plus the time * needed to copy the vector (which is O(n) for n elements in the vector). */ -igraph_error_t FUNCTION(push_back_copy)(TYPE* v, const ITEM_TYPE* e) { +igraph_error_t FUNCTION(push_back_copy)(TYPE *v, const ITEM_TYPE *e) { ITEM_TYPE copy; IGRAPH_CHECK(INTERNAL_FUNCTION(copy_item)(©, e)); IGRAPH_FINALLY(INTERNAL_FUNCTION(destroy_item), ©); @@ -592,9 +591,8 @@ igraph_error_t FUNCTION(push_back_copy)(TYPE* v, const ITEM_TYPE* e) { /** * \ingroup vector_list * \function igraph_vector_list_push_back_new - * \brief Append a new vector to the list. + * \brief Appends a new vector to the list. * - * * This function resizes the list to be one element longer. The newly added * element will be an empty vector that is owned by the list. A pointer to * the newly added element is returned in the last argument if it is not @@ -609,7 +607,7 @@ igraph_error_t FUNCTION(push_back_copy)(TYPE* v, const ITEM_TYPE* e) { * * Time complexity: same as \ref igraph_vector_list_push_back(). */ -igraph_error_t FUNCTION(push_back_new)(TYPE* v, ITEM_TYPE** e) { +igraph_error_t FUNCTION(push_back_new)(TYPE *v, ITEM_TYPE** e) { IGRAPH_CHECK(INTERNAL_FUNCTION(expand_if_full)(v)); IGRAPH_CHECK(INTERNAL_FUNCTION(init_item)(v, v->end)); if (e) { @@ -622,9 +620,8 @@ igraph_error_t FUNCTION(push_back_new)(TYPE* v, ITEM_TYPE** e) { /** * \ingroup vector_list * \function igraph_vector_list_insert - * \brief Insert an existing vector into the list, transferring ownership. + * \brief Inserts an existing vector into the list, transferring ownership. * - * * This function inserts \p e into the list at the given index, moving other * items towards the end of the list as needed. The list takes ownership * of the vector so the user is not responsible for freeing \p e any more; @@ -639,7 +636,7 @@ igraph_error_t FUNCTION(push_back_new)(TYPE* v, ITEM_TYPE** e) { * * Time complexity: O(n). */ -igraph_error_t FUNCTION(insert)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e) { +igraph_error_t FUNCTION(insert)(TYPE *v, igraph_integer_t pos, ITEM_TYPE *e) { igraph_integer_t size = FUNCTION(size)(v); IGRAPH_ASSERT(0 <= pos && pos <= size); IGRAPH_CHECK(INTERNAL_FUNCTION(expand_if_full)(v)); @@ -654,9 +651,8 @@ igraph_error_t FUNCTION(insert)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e) { /** * \ingroup vector_list * \function igraph_vector_list_insert_copy - * \brief Insert the copy of a vector to the list. + * \brief Inserts the copy of a vector to the list. * - * * This function inserts a copy of \p e into the list at the given index, moving * other items towards the end of the list as needed. The newly added * element is owned by the list, but the ownership of the original vector is @@ -671,7 +667,7 @@ igraph_error_t FUNCTION(insert)(TYPE* v, igraph_integer_t pos, ITEM_TYPE* e) { * Time complexity: same as \ref igraph_vector_list_insert() plus the time * needed to copy the vector (which is O(n) for n elements in the vector). */ -igraph_error_t FUNCTION(insert_copy)(TYPE* v, igraph_integer_t pos, const ITEM_TYPE* e) { +igraph_error_t FUNCTION(insert_copy)(TYPE *v, igraph_integer_t pos, const ITEM_TYPE *e) { ITEM_TYPE copy; IGRAPH_CHECK(INTERNAL_FUNCTION(copy_item)(©, e)); IGRAPH_FINALLY(INTERNAL_FUNCTION(destroy_item), ©); @@ -683,9 +679,8 @@ igraph_error_t FUNCTION(insert_copy)(TYPE* v, igraph_integer_t pos, const ITEM_T /** * \ingroup vector_list * \function igraph_vector_list_insert_new - * \brief Insert a new vector into the list. + * \brief Inserts a new vector into the list. * - * * This function inserts a newly created empty vector into the list at the given * index, moving other items towards the end of the list as needed. The newly * added vector is owned by the list. A pointer to the new element is returned @@ -701,7 +696,7 @@ igraph_error_t FUNCTION(insert_copy)(TYPE* v, igraph_integer_t pos, const ITEM_T * * Time complexity: same as \ref igraph_vector_list_push_back(). */ -igraph_error_t FUNCTION(insert_new)(TYPE* v, igraph_integer_t pos, ITEM_TYPE** e) { +igraph_error_t FUNCTION(insert_new)(TYPE *v, igraph_integer_t pos, ITEM_TYPE** e) { ITEM_TYPE copy; IGRAPH_CHECK(INTERNAL_FUNCTION(init_item)(v, ©)); IGRAPH_FINALLY(INTERNAL_FUNCTION(destroy_item), ©); @@ -716,9 +711,8 @@ igraph_error_t FUNCTION(insert_new)(TYPE* v, igraph_integer_t pos, ITEM_TYPE** e /** * \ingroup vector_list * \function igraph_vector_list_remove - * \brief Remove the item at the given index from the vector list and transfer ownership to the caller. + * \brief Removes the item at the given index from the vector list and transfer ownership to the caller. * - * * This function removes the vector at the given index from the list, and * moves all subsequent items in the list by one slot to the left to fill * the gap. The vector that was removed from the list is returned in \p e @@ -727,7 +721,7 @@ igraph_error_t FUNCTION(insert_new)(TYPE* v, igraph_integer_t pos, ITEM_TYPE** e * * \param v The list object. * \param index Index of the item to be removed. - * \param result Pointer to an \c igraph_vector_t object; it will be updated to the + * \param result Pointer to an \ref igraph_vector_t object; it will be updated to the * item that was removed from the list. Ownership of this vector is * passed on to the caller. It is an error to supply a null pointer here. * \sa \ref igraph_vector_list_discard() if you are not interested in the item @@ -736,7 +730,7 @@ igraph_error_t FUNCTION(insert_new)(TYPE* v, igraph_integer_t pos, ITEM_TYPE** e * * Time complexity: O(n), where n is the number of items in the list. */ -igraph_error_t FUNCTION(remove)(TYPE* v, igraph_integer_t index, ITEM_TYPE* result) { +igraph_error_t FUNCTION(remove)(TYPE *v, igraph_integer_t index, ITEM_TYPE *result) { igraph_integer_t size = FUNCTION(size)(v); IGRAPH_ASSERT(result != 0); @@ -756,9 +750,8 @@ igraph_error_t FUNCTION(remove)(TYPE* v, igraph_integer_t index, ITEM_TYPE* resu /** * \ingroup vector_list * \function igraph_vector_list_pop_back - * \brief Remove the last item from the vector list and transfer ownership to the caller. + * \brief Removes the last item from the vector list and transfer ownership to the caller. * - * * This function removes the last vector from the list. The vector that was * removed from the list is returned and its ownership is passed back to the * caller; in other words, the caller becomes responsible for destroying @@ -768,13 +761,13 @@ igraph_error_t FUNCTION(remove)(TYPE* v, igraph_integer_t index, ITEM_TYPE* resu * It is an error to call this function with an empty vector. * * \param v The list object. - * \param result Pointer to an \c igraph_vector_t object; it will be updated to the + * \param result Pointer to an \ref igraph_vector_t object; it will be updated to the * item that was removed from the list. Ownership of this vector is * passed on to the caller. * * Time complexity: O(1). */ -ITEM_TYPE FUNCTION(pop_back)(TYPE* v) { +ITEM_TYPE FUNCTION(pop_back)(TYPE *v) { IGRAPH_ASSERT(!FUNCTION(empty)(v)); v->end -= 1; return *(v->end); @@ -783,9 +776,8 @@ ITEM_TYPE FUNCTION(pop_back)(TYPE* v) { /** * \ingroup vector_list * \function igraph_vector_list_remove_fast - * \brief Remove the item at the given index in the vector list, move the last item to its place and transfer ownership to the caller. + * \brief Removes the item at the given index in the vector list, move the last item to its place and transfer ownership to the caller. * - * * This function removes the vector at the given index from the list, * moves the last item in the list to \p index to fill the gap, and then * transfers ownership of the removed vector back to the caller; in other words, @@ -794,7 +786,7 @@ ITEM_TYPE FUNCTION(pop_back)(TYPE* v) { * * \param v The list object. * \param index Index of the item to be removed. - * \param result Pointer to an \c igraph_vector_t object; it will be updated to the + * \param result Pointer to an \ref igraph_vector_t object; it will be updated to the * item that was removed from the list. Ownership of this vector is * passed on to the caller. It is an error to supply a null pointer here. * \sa \ref igraph_vector_list_remove() if you want to preserve the order of the @@ -803,7 +795,7 @@ ITEM_TYPE FUNCTION(pop_back)(TYPE* v) { * * Time complexity: O(1). */ -igraph_error_t FUNCTION(remove_fast)(TYPE* v, igraph_integer_t index, ITEM_TYPE* result) { +igraph_error_t FUNCTION(remove_fast)(TYPE *v, igraph_integer_t index, ITEM_TYPE *result) { igraph_integer_t size = FUNCTION(size)(v); IGRAPH_ASSERT(result != 0); @@ -848,8 +840,8 @@ igraph_error_t FUNCTION(remove_fast)(TYPE* v, igraph_integer_t index, ITEM_TYPE* * * Time complexity: O(n), the number of items in the list. */ -igraph_error_t FUNCTION(permute)(TYPE* v, const igraph_vector_int_t* index) { - ITEM_TYPE* work; +igraph_error_t FUNCTION(permute)(TYPE *v, const igraph_vector_int_t* index) { + ITEM_TYPE *work; igraph_integer_t i, size; IGRAPH_ASSERT(v != NULL); @@ -1026,16 +1018,16 @@ igraph_error_t FUNCTION(reverse)(TYPE *v) { #ifndef CUSTOM_INIT_DESTROY -static igraph_error_t INTERNAL_FUNCTION(init_item)(const TYPE* list, ITEM_TYPE* item) { +static igraph_error_t INTERNAL_FUNCTION(init_item)(const TYPE *list, ITEM_TYPE *item) { IGRAPH_UNUSED(list); return ITEM_FUNCTION(init)(item, 0); } -static igraph_error_t INTERNAL_FUNCTION(copy_item)(ITEM_TYPE* dest, const ITEM_TYPE* source) { +static igraph_error_t INTERNAL_FUNCTION(copy_item)(ITEM_TYPE *dest, const ITEM_TYPE *source) { return ITEM_FUNCTION(init_copy)(dest, source); } -static void INTERNAL_FUNCTION(destroy_item)(ITEM_TYPE* item) { +static void INTERNAL_FUNCTION(destroy_item)(ITEM_TYPE *item) { ITEM_FUNCTION(destroy)(item); } @@ -1043,8 +1035,8 @@ static void INTERNAL_FUNCTION(destroy_item)(ITEM_TYPE* item) { /* ************************************************************************ */ -static igraph_error_t INTERNAL_FUNCTION(init_slice)(const TYPE* list, ITEM_TYPE* start, ITEM_TYPE* end) { - ITEM_TYPE* current; +static igraph_error_t INTERNAL_FUNCTION(init_slice)(const TYPE *list, ITEM_TYPE *start, ITEM_TYPE *end) { + ITEM_TYPE *current; igraph_error_t retval; for (current = start; current < end; current++) { @@ -1058,7 +1050,7 @@ static igraph_error_t INTERNAL_FUNCTION(init_slice)(const TYPE* list, ITEM_TYPE* return IGRAPH_SUCCESS; } -static void INTERNAL_FUNCTION(destroy_slice)(const TYPE* list, ITEM_TYPE* start, ITEM_TYPE* end) { +static void INTERNAL_FUNCTION(destroy_slice)(const TYPE *list, ITEM_TYPE *start, ITEM_TYPE *end) { IGRAPH_UNUSED(list); for (; start < end; start++) { INTERNAL_FUNCTION(destroy_item)(start); @@ -1069,7 +1061,7 @@ static void INTERNAL_FUNCTION(destroy_slice)(const TYPE* list, ITEM_TYPE* start, * Ensures that the vector has at least one extra slot at the end of its * allocated storage area. */ -static igraph_error_t INTERNAL_FUNCTION(expand_if_full)(TYPE* v) { +static igraph_error_t INTERNAL_FUNCTION(expand_if_full)(TYPE *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -1089,7 +1081,7 @@ static igraph_error_t INTERNAL_FUNCTION(expand_if_full)(TYPE* v) { } /** - * Helper function passed to qsort from igraph_vector_qsort_ind + * Helper function passed to qsort from igraph_vector_list_sort_ind */ static int INTERNAL_FUNCTION(sort_ind_cmp)(void *thunk, const void *p1, const void *p2) { int (*cmp)(const ITEM_TYPE*, const ITEM_TYPE*) = (int (*)(const ITEM_TYPE*, const ITEM_TYPE*)) thunk; diff --git a/src/vendor/cigraph/src/core/vector.pmt b/src/vendor/cigraph/src/core/vector.pmt index 8bc0dd0860..5d1adf3cf3 100644 --- a/src/vendor/cigraph/src/core/vector.pmt +++ b/src/vendor/cigraph/src/core/vector.pmt @@ -132,7 +132,7 @@ * n is the number of elements. */ -igraph_error_t FUNCTION(igraph_vector, init)(TYPE(igraph_vector)* v, igraph_integer_t size) { +igraph_error_t FUNCTION(igraph_vector, init)(TYPE(igraph_vector) *v, igraph_integer_t size) { igraph_integer_t alloc_size; IGRAPH_ASSERT(size >= 0); alloc_size = size > 0 ? size : 1; @@ -171,7 +171,7 @@ igraph_error_t FUNCTION(igraph_vector, init)(TYPE(igraph_vector)* v, igraph_inte * Time complexity: O(1) */ -const TYPE(igraph_vector)* FUNCTION(igraph_vector, view) (const TYPE(igraph_vector) *v, +const TYPE(igraph_vector)* FUNCTION(igraph_vector, view)(const TYPE(igraph_vector) *v, const BASE *data, igraph_integer_t length) { static const BASE dummy = ZERO; TYPE(igraph_vector) *v2 = (TYPE(igraph_vector)*)v; @@ -397,7 +397,7 @@ igraph_error_t FUNCTION(igraph_vector, init_int_end)(TYPE(igraph_vector) *v, int * Time complexity: operating system dependent. */ -void FUNCTION(igraph_vector, destroy) (TYPE(igraph_vector)* v) { +void FUNCTION(igraph_vector, destroy)(TYPE(igraph_vector) *v) { IGRAPH_ASSERT(v != NULL); /* vector_init() will leave stor_begin set to NULL when it fails. * We handle these cases gracefully. */ @@ -425,7 +425,7 @@ void FUNCTION(igraph_vector, destroy) (TYPE(igraph_vector)* v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector)*v) { +igraph_integer_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector) *v) { return v->stor_end - v->stor_begin; } @@ -457,7 +457,7 @@ igraph_integer_t FUNCTION(igraph_vector, capacity)(const TYPE(igraph_vector)*v) * is the new allocated size of the vector. */ -igraph_error_t FUNCTION(igraph_vector, reserve)(TYPE(igraph_vector)* v, igraph_integer_t capacity) { +igraph_error_t FUNCTION(igraph_vector, reserve)(TYPE(igraph_vector) *v, igraph_integer_t capacity) { igraph_integer_t current_capacity; BASE *tmp; @@ -492,7 +492,7 @@ igraph_error_t FUNCTION(igraph_vector, reserve)(TYPE(igraph_vector)* v, igraph_i * Time complexity: O(1). */ -igraph_bool_t FUNCTION(igraph_vector, empty)(const TYPE(igraph_vector)* v) { +igraph_bool_t FUNCTION(igraph_vector, empty)(const TYPE(igraph_vector) *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->stor_begin == v->end; @@ -501,7 +501,9 @@ igraph_bool_t FUNCTION(igraph_vector, empty)(const TYPE(igraph_vector)* v) { /** * \ingroup vector * \function igraph_vector_size - * \brief Returns the size (=length) of the vector. + * \brief The size of the vector. + * + * Returns the number of elements stored in the vector. * * \param v The vector object * \return The size of the vector. @@ -509,7 +511,7 @@ igraph_bool_t FUNCTION(igraph_vector, empty)(const TYPE(igraph_vector)* v) { * Time complexity: O(1). */ -igraph_integer_t FUNCTION(igraph_vector, size)(const TYPE(igraph_vector)* v) { +igraph_integer_t FUNCTION(igraph_vector, size)(const TYPE(igraph_vector) *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->end - v->stor_begin; @@ -540,9 +542,9 @@ void FUNCTION(igraph_vector, clear)(TYPE(igraph_vector)* v) { * \function igraph_vector_push_back * \brief Appends one element to a vector. * - * * 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: @@ -560,7 +562,7 @@ void FUNCTION(igraph_vector, clear)(TYPE(igraph_vector)* v) { * complexity of memory allocation is at most linear.) */ -igraph_error_t FUNCTION(igraph_vector, push_back) (TYPE(igraph_vector)* v, BASE e) { +igraph_error_t FUNCTION(igraph_vector, push_back)(TYPE(igraph_vector) *v, BASE e) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -646,7 +648,7 @@ igraph_error_t FUNCTION(igraph_vector, insert)( * Time complexity: O(1). */ -BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector)* v, igraph_integer_t pos) { +BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return * (v->stor_begin + pos); @@ -669,7 +671,7 @@ BASE FUNCTION(igraph_vector, get)(const TYPE(igraph_vector)* v, igraph_integer_t * Time complexity: O(1). */ -BASE* FUNCTION(igraph_vector, get_ptr) (const TYPE(igraph_vector)* v, igraph_integer_t pos) { +BASE* FUNCTION(igraph_vector, get_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); return v->stor_begin + pos; @@ -683,7 +685,7 @@ BASE* FUNCTION(igraph_vector, get_ptr) (const TYPE(igraph_vector)* v, igraph_in * \deprecated-by igraph_vector_get 0.10.0 */ -BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector)* v, igraph_integer_t pos) { +BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { return FUNCTION(igraph_vector, get)(v, pos); } @@ -701,7 +703,7 @@ BASE FUNCTION(igraph_vector, e)(const TYPE(igraph_vector)* v, igraph_integer_t p * Time complexity: O(1). */ -BASE* FUNCTION(igraph_vector, e_ptr) (const TYPE(igraph_vector)* v, igraph_integer_t pos) { +BASE* FUNCTION(igraph_vector, e_ptr)(const TYPE(igraph_vector) *v, igraph_integer_t pos) { return FUNCTION(igraph_vector, get_ptr)(v, pos); } @@ -719,7 +721,7 @@ BASE* FUNCTION(igraph_vector, e_ptr) (const TYPE(igraph_vector)* v, igraph_inte * \sa \ref igraph_vector_get(). */ -void FUNCTION(igraph_vector, set)(TYPE(igraph_vector)* v, igraph_integer_t pos, BASE value) { +void FUNCTION(igraph_vector, set)(TYPE(igraph_vector) *v, igraph_integer_t pos, BASE value) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); *(v->stor_begin + pos) = value; @@ -742,7 +744,7 @@ void FUNCTION(igraph_vector, set)(TYPE(igraph_vector)* v, igraph_integer_t pos, * the vector. */ -void FUNCTION(igraph_vector, null) (TYPE(igraph_vector)* v) { +void FUNCTION(igraph_vector, null)(TYPE(igraph_vector) *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); if (FUNCTION(igraph_vector, size)(v) > 0) { @@ -762,7 +764,7 @@ void FUNCTION(igraph_vector, null) (TYPE(igraph_vector)* v) { * Time complexity: O(n), the size of the vector. */ -void FUNCTION(igraph_vector, fill) (TYPE(igraph_vector)* v, BASE e) { +void FUNCTION(igraph_vector, fill)(TYPE(igraph_vector) *v, BASE e) { BASE *ptr; IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); @@ -791,13 +793,13 @@ void FUNCTION(igraph_vector, fill) (TYPE(igraph_vector)* v, BASE e) { * Time complexity: O(n), the number of elements in the vector. */ -igraph_error_t FUNCTION(igraph_vector, range)(TYPE(igraph_vector) *v, BASE from, BASE to) { +igraph_error_t FUNCTION(igraph_vector, range)(TYPE(igraph_vector) *v, BASE start, BASE end) { BASE *p; - IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(v, (to - from))); + IGRAPH_CHECK(FUNCTION(igraph_vector, resize)(v, (end - start))); for (p = v->stor_begin; p < v->end; p++) { - *p = from; - from = from + ONE; + *p = start; + start = start + ONE; } return IGRAPH_SUCCESS; @@ -838,7 +840,7 @@ BASE FUNCTION(igraph_vector, tail)(const TYPE(igraph_vector) *v) { * Time complexity: O(1). */ -BASE FUNCTION(igraph_vector, pop_back)(TYPE(igraph_vector)* v) { +BASE FUNCTION(igraph_vector, pop_back)(TYPE(igraph_vector) *v) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); IGRAPH_ASSERT(v->end != NULL); @@ -869,8 +871,8 @@ BASE FUNCTION(igraph_vector, pop_back)(TYPE(igraph_vector)* v) { * * * The index vector that this function takes is compatible with the index vector - * returned from \ref igraph_vector_qsort_ind(); passing in the index vector - * from \ref igraph_vector_qsort_ind() will sort the original vector. + * returned from \ref igraph_vector_sort_ind(); passing in the index vector + * from \ref igraph_vector_sort_ind() will sort the original vector. * * * As a special case, this function allows the index vector to be \em shorter @@ -885,7 +887,7 @@ BASE FUNCTION(igraph_vector, pop_back)(TYPE(igraph_vector)* v) { * * Time complexity: O(n), the size of the vector. */ -igraph_error_t FUNCTION(igraph_vector, permute)(TYPE(igraph_vector)* v, const igraph_vector_int_t* index) { +igraph_error_t FUNCTION(igraph_vector, permute)(TYPE(igraph_vector) *v, const igraph_vector_int_t *index) { IGRAPH_ASSERT(v != NULL); IGRAPH_ASSERT(v->stor_begin != NULL); IGRAPH_ASSERT(index != NULL); @@ -987,9 +989,9 @@ void FUNCTION(igraph_vector, reverse_sort)(TYPE(igraph_vector) *v) { } /** - * Ascending comparison function passed to qsort from igraph_vector_qsort_ind + * Ascending comparison function passed to qsort from igraph_vector_sort_ind */ -static int FUNCTION(igraph_vector, i_qsort_ind_cmp_asc)(const void *p1, const void *p2) { +static int FUNCTION(igraph_vector, i_sort_ind_cmp_asc)(const void *p1, const void *p2) { BASE **pa = (BASE **) p1; BASE **pb = (BASE **) p2; if ( **pa < **pb ) { @@ -1002,9 +1004,9 @@ static int FUNCTION(igraph_vector, i_qsort_ind_cmp_asc)(const void *p1, const vo } /** - * Descending comparison function passed to qsort from igraph_vector_qsort_ind + * Descending comparison function passed to qsort from igraph_vector_sort_ind */ -static int FUNCTION(igraph_vector, i_qsort_ind_cmp_desc)(const void *p1, const void *p2) { +static int FUNCTION(igraph_vector, i_sort_ind_cmp_desc)(const void *p1, const void *p2) { BASE **pa = (BASE **) p1; BASE **pb = (BASE **) p2; if ( **pa < **pb ) { @@ -1017,7 +1019,7 @@ static int FUNCTION(igraph_vector, i_qsort_ind_cmp_desc)(const void *p1, const v } /** - * \function igraph_vector_qsort_ind + * \function igraph_vector_sort_ind * \brief Returns a permutation of indices that sorts a vector. * * Takes an unsorted array \c v as input and computes an array of indices @@ -1042,8 +1044,11 @@ static int FUNCTION(igraph_vector, i_qsort_ind_cmp_desc)(const void *p1, const v * position in the array. Use this to set the values of inds. */ -igraph_error_t FUNCTION(igraph_vector, qsort_ind)(const TYPE(igraph_vector) *v, - igraph_vector_int_t *inds, igraph_order_t order) { +igraph_error_t FUNCTION(igraph_vector, sort_ind)( + const TYPE(igraph_vector) *v, + igraph_vector_int_t *inds, + igraph_order_t order) { + igraph_integer_t i, n = FUNCTION(igraph_vector, size)(v); BASE **vind, *first; IGRAPH_CHECK(igraph_vector_int_resize(inds, n)); @@ -1052,16 +1057,16 @@ igraph_error_t FUNCTION(igraph_vector, qsort_ind)(const TYPE(igraph_vector) *v, } vind = IGRAPH_CALLOC(n, BASE*); if (vind == 0) { - IGRAPH_ERROR("igraph_vector_qsort_ind failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ + IGRAPH_ERROR("igraph_vector_sort_ind failed", IGRAPH_ENOMEM); /* LCOV_EXCL_LINE */ } for (i = 0; i < n; i++) { vind[i] = &VECTOR(*v)[i]; } first = vind[0]; if (order == IGRAPH_ASCENDING) { - igraph_qsort(vind, n, sizeof(BASE*), FUNCTION(igraph_vector, i_qsort_ind_cmp_asc)); + igraph_qsort(vind, n, sizeof(BASE*), FUNCTION(igraph_vector, i_sort_ind_cmp_asc)); } else { - igraph_qsort(vind, n, sizeof(BASE*), FUNCTION(igraph_vector, i_qsort_ind_cmp_desc)); + igraph_qsort(vind, n, sizeof(BASE*), FUNCTION(igraph_vector, i_sort_ind_cmp_desc)); } for (i = 0; i < n; i++) { VECTOR(*inds)[i] = vind[i] - first; @@ -1070,6 +1075,17 @@ igraph_error_t FUNCTION(igraph_vector, qsort_ind)(const TYPE(igraph_vector) *v, return IGRAPH_SUCCESS; } +/** + * \function igraph_vector_qsort_ind + * \brief Returns a permutation of indices that sorts a vector (deprecated alias). + * + * \deprecated-by igraph_vector_sort_ind 0.10.14 + */ +igraph_error_t FUNCTION(igraph_vector, qsort_ind)(const TYPE(igraph_vector) *v, + igraph_vector_int_t *inds, igraph_order_t order) { + return FUNCTION(igraph_vector, sort_ind)(v, inds, order); +} + /** * \function igraph_vector_lex_cmp * \brief Lexicographical comparison of two vectors (type-safe variant). @@ -1288,7 +1304,7 @@ igraph_error_t FUNCTION(igraph_vector, resize)(TYPE(igraph_vector)* v, igraph_in * Time complexity: operating system dependent, O(n) at worst. */ -void FUNCTION(igraph_vector, resize_min)(TYPE(igraph_vector)*v) { +void FUNCTION(igraph_vector, resize_min)(TYPE(igraph_vector) *v) { igraph_integer_t size; BASE *tmp; if (v->stor_end == v->end) { @@ -1326,7 +1342,7 @@ void FUNCTION(igraph_vector, resize_min)(TYPE(igraph_vector)*v) { * * Time complexity: O(n), the number of elements. */ -BASE FUNCTION(igraph_vector, max)(const TYPE(igraph_vector)* v) { +BASE FUNCTION(igraph_vector, max)(const TYPE(igraph_vector) *v) { BASE max; BASE *ptr; IGRAPH_ASSERT(!FUNCTION(igraph_vector, empty)(v)); @@ -1364,7 +1380,7 @@ BASE FUNCTION(igraph_vector, max)(const TYPE(igraph_vector)* v) { * * Time complexity: O(n), n is the size of the vector. */ -igraph_integer_t FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector)* v) { +igraph_integer_t FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector) *v) { BASE *max; BASE *ptr; IGRAPH_ASSERT(!FUNCTION(igraph_vector, empty)(v)); @@ -1400,7 +1416,7 @@ igraph_integer_t FUNCTION(igraph_vector, which_max)(const TYPE(igraph_vector)* v * Time complexity: O(n), the number of elements. */ -BASE FUNCTION(igraph_vector, min)(const TYPE(igraph_vector)* v) { +BASE FUNCTION(igraph_vector, min)(const TYPE(igraph_vector) *v) { BASE min; BASE *ptr; IGRAPH_ASSERT(!FUNCTION(igraph_vector, empty)(v)); @@ -1569,8 +1585,8 @@ igraph_error_t FUNCTION(igraph_vector, copy)(TYPE(igraph_vector) *to, * \function igraph_vector_sum * \brief Calculates the sum of the elements in the vector. * - * - * For the empty vector 0.0 is returned. + * For the empty vector 0 is returned. + * * \param v The vector object. * \return The sum of the elements. * @@ -1729,13 +1745,13 @@ igraph_error_t FUNCTION(igraph_vector, init_seq)(TYPE(igraph_vector) *v, BASE fr * Time complexity: O(n), the number of elements in the vector. */ -igraph_error_t FUNCTION(igraph_vector, init_range)(TYPE(igraph_vector) *v, BASE from, BASE to) { +igraph_error_t FUNCTION(igraph_vector, init_range)(TYPE(igraph_vector) *v, BASE start, BASE end) { BASE *p; - IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, (to - from))); + IGRAPH_CHECK(FUNCTION(igraph_vector, init)(v, (end - start))); for (p = v->stor_begin; p < v->end; p++) { - *p = from; - from = from + ONE; + *p = start; + start = start + ONE; } return IGRAPH_SUCCESS; @@ -1943,7 +1959,7 @@ igraph_bool_t FUNCTION(igraph_vector, any_smaller)(const TYPE(igraph_vector) *v, */ igraph_bool_t FUNCTION(igraph_vector, all_e)(const TYPE(igraph_vector) *lhs, - const TYPE(igraph_vector) *rhs) { + const TYPE(igraph_vector) *rhs) { igraph_integer_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); @@ -1969,9 +1985,24 @@ igraph_bool_t FUNCTION(igraph_vector, all_e)(const TYPE(igraph_vector) *lhs, } } -igraph_bool_t -FUNCTION(igraph_vector, is_equal)(const TYPE(igraph_vector) *lhs, - const TYPE(igraph_vector) *rhs) { +/** + * \ingroup vector + * \function igraph_vector_is_equal + * \brief Are all elements equal? + * + * This is an alias of \ref igraph_vector_all_e() with a more intuitive name. + * + * \param lhs The first vector. + * \param rhs The second vector. + * \return True if the elements in the \p lhs are all + * equal to the corresponding elements in \p rhs. Returns + * 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, is_equal)(const TYPE(igraph_vector) *lhs, + const TYPE(igraph_vector) *rhs) { return FUNCTION(igraph_vector, all_e)(lhs, rhs); } @@ -1993,7 +2024,7 @@ FUNCTION(igraph_vector, is_equal)(const TYPE(igraph_vector) *lhs, */ igraph_bool_t FUNCTION(igraph_vector, all_l)(const TYPE(igraph_vector) *lhs, - const TYPE(igraph_vector) *rhs) { + const TYPE(igraph_vector) *rhs) { igraph_integer_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); @@ -2031,7 +2062,7 @@ igraph_bool_t FUNCTION(igraph_vector, all_l)(const TYPE(igraph_vector) *lhs, */ igraph_bool_t FUNCTION(igraph_vector, all_g)(const TYPE(igraph_vector) *lhs, - const TYPE(igraph_vector) *rhs) { + const TYPE(igraph_vector) *rhs) { igraph_integer_t i, s; IGRAPH_ASSERT(lhs != 0); @@ -2069,9 +2100,8 @@ igraph_bool_t FUNCTION(igraph_vector, all_g)(const TYPE(igraph_vector) *lhs, * 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) { +igraph_bool_t FUNCTION(igraph_vector, all_le)(const TYPE(igraph_vector) *lhs, + const TYPE(igraph_vector) *rhs) { igraph_integer_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); @@ -2108,9 +2138,8 @@ FUNCTION(igraph_vector, all_le)(const TYPE(igraph_vector) *lhs, * 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) { +igraph_bool_t FUNCTION(igraph_vector, all_ge)(const TYPE(igraph_vector) *lhs, + const TYPE(igraph_vector) *rhs) { igraph_integer_t i, s; IGRAPH_ASSERT(lhs != 0); IGRAPH_ASSERT(rhs != 0); @@ -2250,11 +2279,11 @@ static igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igrap /** * \ingroup vector - * \function igraph_vector_binsearch2 - * \brief Binary search, without returning the index. + * \function igraph_vector_contains_sorted + * \brief Binary search in a sorted vector. * - * * It is assumed that the vector is sorted. + * * \param v The \type igraph_vector_t object. * \param what The element to search for. * \return True if \p what is found in the vector, false otherwise. @@ -2262,8 +2291,7 @@ static igraph_bool_t FUNCTION(igraph_i_vector, binsearch_slice)(const TYPE(igrap * 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) { +igraph_bool_t FUNCTION(igraph_vector, contains_sorted)(const TYPE(igraph_vector) *v, BASE what) { igraph_integer_t left = 0; igraph_integer_t right = FUNCTION(igraph_vector, size)(v) - 1; @@ -2282,6 +2310,18 @@ igraph_bool_t FUNCTION(igraph_vector, binsearch2)(const TYPE(igraph_vector) *v, return false; } +/** + * \ingroup vector + * \function igraph_vector_binsearch2 + * \brief Binary search, without returning the index. + * + * \deprecated-by igraph_vector_contains_sorted 0.10.14 + */ +igraph_bool_t FUNCTION(igraph_vector, binsearch2)(const TYPE(igraph_vector) *v, + BASE what) { + return FUNCTION(igraph_vector, contains_sorted)(v, what); +} + #endif /** @@ -2337,21 +2377,22 @@ void FUNCTION(igraph_vector, add_constant)(TYPE(igraph_vector) *v, BASE plus) { * * 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. + * \param what 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; + BASE what) { + const BASE *p = v->stor_begin; while (p < v->end) { #ifdef EQ - if (EQ(*p, e)) { + if (EQ(*p, what)) { #else - if (*p == e) { + if (*p == what) { #endif return true; } @@ -2583,31 +2624,74 @@ igraph_error_t FUNCTION(igraph_vector, swap_elements)(TYPE(igraph_vector) *v, return IGRAPH_SUCCESS; } +/** + * \function igraph_vector_reverse_section + * \brief Reverse the elements in a section of a vector. + * + * \param v The input vector. + * \param from Index of the first element to include in the reversal. + * \param to Index of the first element \em not to include in the reversal. + * + * \sa igraph_vector_reverse() to reverse the entire vector. + * + * Time complexity: O(to - from), the number of elements to reverse. + */ + +void FUNCTION(igraph_vector, reverse_section)(TYPE(igraph_vector) *v, igraph_integer_t from, igraph_integer_t to) { + const igraph_integer_t mid = (from + to) / 2; + for (igraph_integer_t i = from, j = to - 1; i < mid; i++, j--) { + BASE tmp = VECTOR(*v)[i]; + VECTOR(*v)[i] = VECTOR(*v)[j]; + VECTOR(*v)[j] = tmp; + } +} + /** * \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. * + * \sa igraph_vector_reverse_section() to reverse only a section of a vector. + * * Time complexity: O(n), the number of elements. */ igraph_error_t FUNCTION(igraph_vector, reverse)(TYPE(igraph_vector) *v) { - - igraph_integer_t n = FUNCTION(igraph_vector, size)(v), n2 = n / 2; - igraph_integer_t 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; - } + FUNCTION(igraph_vector, reverse_section)(v, 0, FUNCTION(igraph_vector, size)(v)); return IGRAPH_SUCCESS; } +/** + * \function igraph_vector_rotate_left + * \brief Rotates the elements of a vector to the left. + * + * Rotates the elements of a vector to the left by the given number of steps. + * Element index \p n will have index 0 after the rotation. + * For example, rotating (0, 1, 2, 3, 4, 5) by 2 yields + * (2, 3, 4, 5, 0, 1). + * + * \param v The input vector. + * \param n The number of steps to rotate by. Passing a negative value rotates + * to the right. + * + * Time complexity: O(n), the number of elements. + */ + +void FUNCTION(igraph_vector, rotate_left)(TYPE(igraph_vector) *v, igraph_integer_t n) { + const igraph_integer_t size = FUNCTION(igraph_vector, size)(v); + n = n % size; + if (n < 0) n += size; + if (n == 0) return; + FUNCTION(igraph_vector, reverse_section)(v, 0, n); + FUNCTION(igraph_vector, reverse_section)(v, n, size); + FUNCTION(igraph_vector, reverse_section)(v, 0, size); +} + /** * \ingroup vector * \function igraph_vector_shuffle @@ -2838,7 +2922,7 @@ igraph_error_t FUNCTION(igraph_vector, abs)(TYPE(igraph_vector) *v) { */ void FUNCTION(igraph_vector, minmax)(const TYPE(igraph_vector) *v, - BASE *min, BASE *max) { + BASE *min, BASE *max) { BASE* ptr; IGRAPH_ASSERT(!FUNCTION(igraph_vector, empty)(v)); *min = *max = *(v->stor_begin); diff --git a/src/vendor/cigraph/src/games/chung_lu.c b/src/vendor/cigraph/src/games/chung_lu.c index c3af93dc2e..f0bcdc56a8 100644 --- a/src/vendor/cigraph/src/games/chung_lu.c +++ b/src/vendor/cigraph/src/games/chung_lu.c @@ -90,7 +90,7 @@ static igraph_error_t check_expected_degrees(const igraph_vector_t *weights) { * * A limitation of the original Chung-Lu model is that when some of the * weights are large, the formula for \c p_ij yields values larger than 1. - * Chung and Lu's original paper exludes the use of such weights. When + * Chung and Lu's original paper excludes the use of such weights. When * p_ij > 1, this function simply issues a warning and creates * a connection between \c i and \c j. However, in this case the expected degrees * will no longer relate to the weights in the manner stated above. Thus the @@ -110,8 +110,8 @@ static igraph_error_t check_expected_degrees(const igraph_vector_t *weights) { * a constraint on expected degrees; see Park and Newman (2004), Section B, * setting exp(-Theta_ij) = w_i w_j / S. This model is also * discussed by Britton, Deijfen and Martin-Löf (2006). By virtue of being - * a degree-constrained maximum entropy model, it graphs with the same degree - * sequence are produced with the same probability. + * a degree-constrained maximum entropy model, it produces graphs with the + * same degree sequence with the same probability. * A third variant can be requested with \c IGRAPH_CHUNG_LU_NR, and uses * p_ij = 1 - exp(-q_ij). This is the underlying simple graph * of a multigraph model introduced by Norros and Reittu (2006). @@ -232,7 +232,7 @@ igraph_error_t igraph_chung_lu_game(igraph_t *graph, IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&idx, 0); - igraph_vector_qsort_ind(in_weights, &idx, IGRAPH_DESCENDING); + igraph_vector_sort_ind(in_weights, &idx, IGRAPH_DESCENDING); RNG_BEGIN(); for (igraph_integer_t i=0; i < no_of_nodes; i++) { diff --git a/src/vendor/cigraph/src/games/dotproduct.c b/src/vendor/cigraph/src/games/dotproduct.c index 88587afa5c..fe1b5b853b 100644 --- a/src/vendor/cigraph/src/games/dotproduct.c +++ b/src/vendor/cigraph/src/games/dotproduct.c @@ -81,7 +81,7 @@ igraph_error_t igraph_dot_product_game(igraph_t *graph, const igraph_matrix_t *v continue; } igraph_vector_view(&v2, &MATRIX(*vecs, 0, j), nrow); - igraph_blas_ddot(&v1, &v2, &prob); + IGRAPH_CHECK(igraph_blas_ddot(&v1, &v2, &prob)); if (prob < 0 && ! warned_neg) { warned_neg = true; IGRAPH_WARNING("Negative connection probability in dot-product graph."); diff --git a/src/vendor/cigraph/src/games/watts_strogatz.c b/src/vendor/cigraph/src/games/watts_strogatz.c index 6647296b35..dbfee3e543 100644 --- a/src/vendor/cigraph/src/games/watts_strogatz.c +++ b/src/vendor/cigraph/src/games/watts_strogatz.c @@ -51,8 +51,9 @@ * * * Duncan J Watts and Steven H Strogatz: - * Collective dynamics of small world networks, Nature - * 393, 440-442, 1998. + * Collective dynamics of small world networks, + * Nature 393, 440-442, 1998. + * https://doi.org/10.1038/30918 * * \param graph The graph to initialize. * \param dim The dimension of the lattice. diff --git a/src/vendor/cigraph/src/graph/adjlist.c b/src/vendor/cigraph/src/graph/adjlist.c index f0275588fb..c0b94154ed 100644 --- a/src/vendor/cigraph/src/graph/adjlist.c +++ b/src/vendor/cigraph/src/graph/adjlist.c @@ -562,15 +562,33 @@ igraph_error_t igraph_adjlist_fprint(const igraph_adjlist_t *al, FILE *outfile) } \ } 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; +/** + * \function igraph_adjlist_has_edge + * \brief Checks if an adjacency list contains an edge. + * + * \param al The adjacency list. It must be sorted. + * \param from The source vertex of the edge. + * \param to The target vertex of the edge. + * \param directed Whether to treat the graph as directed. + * \return + */ + +igraph_bool_t igraph_adjlist_has_edge( + igraph_adjlist_t* al, + igraph_integer_t from, igraph_integer_t to, + igraph_bool_t directed) { + + const igraph_vector_int_t *fromvec; ADJLIST_CANON_EDGE(from, to, directed); fromvec = igraph_adjlist_get(al, from); - return igraph_vector_int_binsearch2(fromvec, to); - + return igraph_vector_int_contains_sorted(fromvec, to); } -igraph_error_t 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_error_t 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; igraph_bool_t found_old, found_new; igraph_integer_t oldpos, newpos; diff --git a/src/vendor/cigraph/src/graph/type_common.c b/src/vendor/cigraph/src/graph/type_common.c index da01c834c2..a2d5f47b7d 100644 --- a/src/vendor/cigraph/src/graph/type_common.c +++ b/src/vendor/cigraph/src/graph/type_common.c @@ -41,7 +41,7 @@ * 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 + * by "empty graph" as used in \a 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 diff --git a/src/vendor/cigraph/src/internal/glpk_support.h b/src/vendor/cigraph/src/internal/glpk_support.h index 9ecc99ac9f..973b6dad61 100644 --- a/src/vendor/cigraph/src/internal/glpk_support.h +++ b/src/vendor/cigraph/src/internal/glpk_support.h @@ -25,7 +25,7 @@ #ifndef IGRAPH_GLPK_SUPPORT_H #define IGRAPH_GLPK_SUPPORT_H -#include "config.h" +#include "config.h" /* HAVE_GLPK, IGRAPH_THREAD_LOCAL */ /* Note: only files calling the GLPK routines directly need to include this header. diff --git a/src/vendor/cigraph/src/internal/gmp_internal.h b/src/vendor/cigraph/src/internal/gmp_internal.h index e7f6b7e35e..5cc0b9910a 100644 --- a/src/vendor/cigraph/src/internal/gmp_internal.h +++ b/src/vendor/cigraph/src/internal/gmp_internal.h @@ -23,7 +23,7 @@ #ifndef IGRAPH_GMP_H #define IGRAPH_GMP_H -#include "config.h" +#include "config.h" /* INTERNAL_GMP */ #ifdef INTERNAL_GMP #include "mini-gmp/mini-gmp.h" diff --git a/src/vendor/cigraph/src/io/dimacs.c b/src/vendor/cigraph/src/io/dimacs.c index 3539db82aa..4de4f40ff2 100644 --- a/src/vendor/cigraph/src/io/dimacs.c +++ b/src/vendor/cigraph/src/io/dimacs.c @@ -120,7 +120,7 @@ igraph_error_t igraph_read_graph_dimacs(igraph_t *graph, FILE *instream, * 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() + * \sa \ref igraph_write_graph_dimacs_flow() */ igraph_error_t igraph_read_graph_dimacs_flow( igraph_t *graph, FILE *instream, @@ -353,21 +353,25 @@ igraph_error_t igraph_write_graph_dimacs_flow(const igraph_t *graph, FILE *outst int ret, ret1, ret2, ret3; if (igraph_vector_size(capacity) != no_of_edges) { - IGRAPH_ERROR("invalid capacity vector length", IGRAPH_EINVAL); + IGRAPH_ERRORF("Capacity vector length (%" IGRAPH_PRId ") " + "does not match edge count (%" IGRAPH_PRId ").", + IGRAPH_EINVAL, + igraph_vector_size(capacity), no_of_edges); } - IGRAPH_CHECK(igraph_eit_create(graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), - &it)); + 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 %" IGRAPH_PRId " %" IGRAPH_PRId "\nn %" IGRAPH_PRId " s\nn %" IGRAPH_PRId " t\n", + "c created by igraph\n" + "p max %" IGRAPH_PRId " %" IGRAPH_PRId "\n" + "n %" IGRAPH_PRId " s\n" + "n %" IGRAPH_PRId " t\n", no_of_nodes, no_of_edges, source + 1, target + 1); if (ret < 0) { - IGRAPH_ERROR("Write error", IGRAPH_EFILE); + IGRAPH_ERROR("Error while writing DIMACS flow file.", IGRAPH_EFILE); } - while (!IGRAPH_EIT_END(it)) { igraph_integer_t from, to; igraph_real_t cap; @@ -378,12 +382,13 @@ igraph_error_t igraph_write_graph_dimacs_flow(const igraph_t *graph, FILE *outst 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_ERROR("Error while writing DIMACS flow file.", IGRAPH_EFILE); } IGRAPH_EIT_NEXT(it); } igraph_eit_destroy(&it); IGRAPH_FINALLY_CLEAN(1); + return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/io/graphml.c b/src/vendor/cigraph/src/io/graphml.c index 80e1a190ae..82285a4dac 100644 --- a/src/vendor/cigraph/src/io/graphml.c +++ b/src/vendor/cigraph/src/io/graphml.c @@ -28,7 +28,7 @@ #include "internal/hacks.h" /* strcasecmp & strdup */ #include "io/parse_utils.h" -#include "config.h" +#include "config.h" /* HAVE_LIBXML */ #include /* isdigit */ #include /* isnan */ diff --git a/src/vendor/cigraph/src/io/pajek-header.h b/src/vendor/cigraph/src/io/pajek-header.h index caa2360e8f..63308777ad 100644 --- a/src/vendor/cigraph/src/io/pajek-header.h +++ b/src/vendor/cigraph/src/io/pajek-header.h @@ -20,6 +20,7 @@ */ +#include "igraph_bitset.h" #include "igraph_error.h" #include "igraph_vector.h" #include "igraph_vector_ptr.h" @@ -48,6 +49,7 @@ typedef struct { char errmsg[300]; igraph_error_t igraph_errno; igraph_vector_int_t *vector; + igraph_bitset_t *seen; igraph_bool_t directed; igraph_integer_t vcount, vcount2; igraph_integer_t actfrom; diff --git a/src/vendor/cigraph/src/io/pajek-parser.y b/src/vendor/cigraph/src/io/pajek-parser.y index d9d377e98b..da13026d14 100644 --- a/src/vendor/cigraph/src/io/pajek-parser.y +++ b/src/vendor/cigraph/src/io/pajek-parser.y @@ -211,6 +211,7 @@ verticeshead: VERTICESLINE integer { if (context->vcount > IGRAPH_PAJEK_MAX_VERTEX_COUNT) { IGRAPH_YY_ERRORF("Vertex count too large in Pajek file (%" IGRAPH_PRId ").", IGRAPH_EINVAL, context->vcount); } + IGRAPH_YY_CHECK(igraph_bitset_resize(context->seen, context->vcount)); } | VERTICESLINE integer integer { context->vcount=$2; @@ -228,12 +229,20 @@ verticeshead: VERTICESLINE integer { IGRAPH_YY_ERRORF("2-mode vertex count too large in Pajek file (%" IGRAPH_PRId ").", IGRAPH_EINVAL, context->vcount2); } IGRAPH_YY_CHECK(add_bipartite_type(context)); + IGRAPH_YY_CHECK(igraph_bitset_resize(context->seen, context->vcount)); }; vertdefs: /* empty */ | vertdefs vertexline; vertexline: vertex NEWLINE | - vertex { context->actvertex=$1; } vertexid vertexcoords shape vertparams NEWLINE { } + vertex { context->actvertex=$1; } vertexid vertexcoords shape vertparams NEWLINE { + igraph_integer_t v = $1-1; /* zero-based vertex ID */ + if (IGRAPH_BIT_TEST(*context->seen, v)) { + IGRAPH_WARNINGF("Vertex ID %" IGRAPH_PRId " appears twice in Pajek file. Duplicate attributes will be overwritten.", v+1); + } else { + IGRAPH_BIT_SET(*context->seen, v); + } + } ; vertex: integer { diff --git a/src/vendor/cigraph/src/io/pajek.c b/src/vendor/cigraph/src/io/pajek.c index d54c293bb8..f3f3e9544c 100644 --- a/src/vendor/cigraph/src/io/pajek.c +++ b/src/vendor/cigraph/src/io/pajek.c @@ -177,6 +177,7 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { igraph_vector_ptr_t eattrs; igraph_integer_t i, j; igraph_i_pajek_parsedata_t context; + igraph_bitset_t seen; /* used to mark already seen vertex IDs */ IGRAPH_VECTOR_INT_INIT_FINALLY(&edges, 0); @@ -188,8 +189,11 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { IGRAPH_CHECK(igraph_vector_ptr_init(&eattrs, 0)); IGRAPH_FINALLY(igraph_i_pajek_destroy_attr_vector, &eattrs); + IGRAPH_BITSET_INIT_FINALLY(&seen, 0); + context.directed = false; /* assume undirected until an element implying directedness is encountered */ context.vector = &edges; + context.seen = &seen; context.vcount = -1; context.vertexid = 0; context.vertex_attribute_names = &vattrnames; @@ -234,6 +238,10 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { IGRAPH_FATALF("Parser returned unexpected error code (%d) when reading Pajek file.", err); } + igraph_pajek_yylex_destroy(context.scanner); + igraph_bitset_destroy(&seen); + IGRAPH_FINALLY_CLEAN(2); + /* Prepare attributes */ const igraph_integer_t eattr_count = igraph_vector_ptr_size(&eattrs); for (i = 0; i < eattr_count; i++) { @@ -275,8 +283,7 @@ igraph_error_t igraph_read_graph_pajek(igraph_t *graph, FILE *instream) { igraph_trie_destroy(&eattrnames); igraph_i_pajek_destroy_attr_vector(&vattrs); igraph_trie_destroy(&vattrnames); - igraph_pajek_yylex_destroy(context.scanner); - IGRAPH_FINALLY_CLEAN(7); /* +1 for 'graph' */ + IGRAPH_FINALLY_CLEAN(6); /* +1 for 'graph' */ return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/io/parse_utils.c b/src/vendor/cigraph/src/io/parse_utils.c index ad2d484328..2b0e0d73da 100644 --- a/src/vendor/cigraph/src/io/parse_utils.c +++ b/src/vendor/cigraph/src/io/parse_utils.c @@ -4,7 +4,7 @@ #include "igraph_foreign.h" #include "igraph_memory.h" -#include "config.h" +#include "config.h" /* HAVE_XLOCALE */ #include #include diff --git a/src/vendor/cigraph/src/isomorphism/vf2.c b/src/vendor/cigraph/src/isomorphism/vf2.c index 782141f004..3e6bb14c99 100644 --- a/src/vendor/cigraph/src/isomorphism/vf2.c +++ b/src/vendor/cigraph/src/isomorphism/vf2.c @@ -460,7 +460,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( if (VECTOR(*core_1)[node] >= 0) { igraph_integer_t node2 = VECTOR(*core_1)[node]; /* check if there is a node2->cand2 edge */ - if (!igraph_vector_int_binsearch2(inneis_2, node2)) { + if (!igraph_vector_int_contains_sorted(inneis_2, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { igraph_integer_t eid1, eid2; @@ -492,7 +492,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( if (VECTOR(*core_1)[node] >= 0) { igraph_integer_t node2 = VECTOR(*core_1)[node]; /* check if there is a cand2->node2 edge */ - if (!igraph_vector_int_binsearch2(outneis_2, node2)) { + if (!igraph_vector_int_contains_sorted(outneis_2, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { igraph_integer_t eid1, eid2; @@ -524,7 +524,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( if (VECTOR(*core_2)[node] >= 0) { igraph_integer_t node2 = VECTOR(*core_2)[node]; /* check if there is a node2->cand1 edge */ - if (!igraph_vector_int_binsearch2(inneis_1, node2)) { + if (!igraph_vector_int_contains_sorted(inneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { igraph_integer_t eid1, eid2; @@ -556,7 +556,7 @@ igraph_error_t igraph_get_isomorphisms_vf2_callback( if (VECTOR(*core_2)[node] >= 0) { igraph_integer_t node2 = VECTOR(*core_2)[node]; /* check if there is a cand1->node2 edge */ - if (!igraph_vector_int_binsearch2(outneis_1, node2)) { + if (!igraph_vector_int_contains_sorted(outneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { igraph_integer_t eid1, eid2; @@ -1361,7 +1361,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( if (VECTOR(*core_2)[node] >= 0) { igraph_integer_t node2 = VECTOR(*core_2)[node]; /* check if there is a node2->cand1 edge */ - if (!igraph_vector_int_binsearch2(inneis_1, node2)) { + if (!igraph_vector_int_contains_sorted(inneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { igraph_integer_t eid1, eid2; @@ -1393,7 +1393,7 @@ igraph_error_t igraph_get_subisomorphisms_vf2_callback( if (VECTOR(*core_2)[node] >= 0) { igraph_integer_t node2 = VECTOR(*core_2)[node]; /* check if there is a cand1->node2 edge */ - if (!igraph_vector_int_binsearch2(outneis_1, node2)) { + if (!igraph_vector_int_contains_sorted(outneis_1, node2)) { end = true; } else if (edge_color1 || edge_compat_fn) { igraph_integer_t eid1, eid2; diff --git a/src/vendor/cigraph/src/layout/fruchterman_reingold.c b/src/vendor/cigraph/src/layout/fruchterman_reingold.c index a676b175c1..1b2aafdda8 100644 --- a/src/vendor/cigraph/src/layout/fruchterman_reingold.c +++ b/src/vendor/cigraph/src/layout/fruchterman_reingold.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* IGraph library. - Copyright (C) 2003-2020 The igraph development team + Copyright (C) 2003-2024 The igraph development 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 @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_layout.h" @@ -42,9 +37,8 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, 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; + const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_integer_t ecount = igraph_ecount(graph); igraph_vector_t dispx, dispy; igraph_real_t temp = start_temp; igraph_real_t difftemp = start_temp / niter; @@ -53,20 +47,18 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK)); if (!conn) { - C = no_nodes * sqrt(no_nodes); + C = vcount * sqrt(vcount); } if (!use_seed) { igraph_i_layout_random_bounded(graph, res, minx, maxx, miny, maxy); } - IGRAPH_VECTOR_INIT_FINALLY(&dispx, no_nodes); - IGRAPH_VECTOR_INIT_FINALLY(&dispy, no_nodes); + IGRAPH_VECTOR_INIT_FINALLY(&dispx, vcount); + IGRAPH_VECTOR_INIT_FINALLY(&dispy, vcount); RNG_BEGIN(); - for (i = 0; i < niter; i++) { - igraph_integer_t v, u, e; - + for (igraph_integer_t i = 0; i < niter; i++) { IGRAPH_ALLOW_INTERRUPTION(); /* calculate repulsive forces, we have a special version @@ -74,8 +66,8 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, igraph_vector_null(&dispx); igraph_vector_null(&dispy); if (conn) { - for (v = 0; v < no_nodes; v++) { - for (u = v + 1; u < no_nodes; u++) { + for (igraph_integer_t v = 0; v < vcount; v++) { + for (igraph_integer_t u = v + 1; u < vcount; u++) { igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dlen = dx * dx + dy * dy; @@ -93,8 +85,8 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, } } } else { - for (v = 0; v < no_nodes; v++) { - for (u = v + 1; u < no_nodes; u++) { + for (igraph_integer_t v = 0; v < vcount; v++) { + for (igraph_integer_t u = v + 1; u < vcount; u++) { igraph_real_t dx = MATRIX(*res, v, 0) - MATRIX(*res, u, 0); igraph_real_t dy = MATRIX(*res, v, 1) - MATRIX(*res, u, 1); igraph_real_t dlen, rdlen; @@ -117,7 +109,7 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, } /* calculate attractive forces */ - for (e = 0; e < no_edges; e++) { + for (igraph_integer_t e = 0; e < ecount; e++) { /* each edge 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); @@ -133,7 +125,7 @@ static igraph_error_t igraph_layout_i_fr(const igraph_t *graph, /* limit max displacement to temperature t and prevent from displacement outside frame */ - for (v = 0; v < no_nodes; v++) { + for (igraph_integer_t v = 0; v < vcount; v++) { igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t displen = sqrt(dx * dx + dy * dy); @@ -180,15 +172,14 @@ static igraph_error_t igraph_layout_i_grid_fr( 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 width = sqrt(no_nodes), height = width; + const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_integer_t ecount = igraph_ecount(graph); + const igraph_real_t width = sqrt(vcount), height = width; igraph_2dgrid_t grid; igraph_vector_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 igraph_real_t cellsize = 2.0; if (!use_seed) { @@ -201,16 +192,16 @@ static igraph_error_t igraph_layout_i_grid_fr( IGRAPH_FINALLY(igraph_2dgrid_destroy, &grid); /* place vertices on grid */ - for (i = 0; i < no_nodes; i++) { + for (igraph_integer_t i = 0; i < vcount; i++) { igraph_2dgrid_add2(&grid, i); } - IGRAPH_VECTOR_INIT_FINALLY(&dispx, no_nodes); - IGRAPH_VECTOR_INIT_FINALLY(&dispy, no_nodes); + IGRAPH_VECTOR_INIT_FINALLY(&dispx, vcount); + IGRAPH_VECTOR_INIT_FINALLY(&dispy, vcount); RNG_BEGIN(); - for (i = 0; i < niter; i++) { - igraph_integer_t v, u, e; + for (igraph_integer_t i = 0; i < niter; i++) { + igraph_integer_t v, u; IGRAPH_ALLOW_INTERRUPTION(); @@ -239,7 +230,7 @@ static igraph_error_t igraph_layout_i_grid_fr( } /* attraction */ - for (e = 0; e < no_edges; e++) { + for (igraph_integer_t e = 0; e < ecount; 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); @@ -253,7 +244,7 @@ static igraph_error_t igraph_layout_i_grid_fr( } /* update */ - for (v = 0; v < no_nodes; v++) { + for (v = 0; v < vcount; v++) { igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t displen = sqrt(dx * dx + dy * dy); @@ -374,40 +365,40 @@ igraph_error_t igraph_layout_fruchterman_reingold(const igraph_t *graph, 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); + const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_integer_t ecount = igraph_ecount(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 || + if (use_seed && (igraph_matrix_nrow(res) != vcount || igraph_matrix_ncol(res) != 2)) { IGRAPH_ERROR("Invalid start position matrix size in " "Fruchterman-Reingold layout.", IGRAPH_EINVAL); } - if (weights && igraph_vector_size(weights) != no_edges) { + if (weights && igraph_vector_size(weights) != ecount) { IGRAPH_ERROR("Invalid weight vector length.", IGRAPH_EINVAL); } - if (weights && no_edges > 0 && igraph_vector_min(weights) <= 0) { + if (weights && ecount > 0 && igraph_vector_min(weights) <= 0) { IGRAPH_ERROR("Weights must be positive for Fruchterman-Reingold layout.", IGRAPH_EINVAL); } - if (minx && igraph_vector_size(minx) != no_nodes) { + if (minx && igraph_vector_size(minx) != vcount) { IGRAPH_ERROR("Invalid minx vector length.", IGRAPH_EINVAL); } - if (maxx && igraph_vector_size(maxx) != no_nodes) { + if (maxx && igraph_vector_size(maxx) != vcount) { 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) { + if (miny && igraph_vector_size(miny) != vcount) { IGRAPH_ERROR("Invalid miny vector length.", IGRAPH_EINVAL); } - if (maxy && igraph_vector_size(maxy) != no_nodes) { + if (maxy && igraph_vector_size(maxy) != vcount) { IGRAPH_ERROR("Invalid maxy vector length.", IGRAPH_EINVAL); } if (miny && maxy && !igraph_vector_all_le(miny, maxy)) { @@ -415,7 +406,7 @@ igraph_error_t igraph_layout_fruchterman_reingold(const igraph_t *graph, } if (grid == IGRAPH_LAYOUT_AUTOGRID) { - if (no_nodes > 1000) { + if (vcount > 1000) { grid = IGRAPH_LAYOUT_GRID; } else { grid = IGRAPH_LAYOUT_NOGRID; @@ -492,9 +483,8 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, const igraph_vector_t *minz, const igraph_vector_t *maxz) { - const igraph_integer_t no_nodes = igraph_vcount(graph); - const igraph_integer_t no_edges = igraph_ecount(graph); - igraph_integer_t i; + const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_integer_t ecount = igraph_ecount(graph); igraph_vector_t dispx, dispy, dispz; igraph_real_t temp = start_temp; igraph_real_t difftemp = start_temp / niter; @@ -506,7 +496,7 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, "Fruchterman-Reingold layout", IGRAPH_EINVAL); } - if (use_seed && (igraph_matrix_nrow(res) != no_nodes || + if (use_seed && (igraph_matrix_nrow(res) != vcount || igraph_matrix_ncol(res) != 3)) { IGRAPH_ERROR("Invalid start position matrix size in " "Fruchterman-Reingold layout", IGRAPH_EINVAL); @@ -515,32 +505,32 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, if (weights && igraph_vector_size(weights) != igraph_ecount(graph)) { IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL); } - if (weights && no_edges > 0 && igraph_vector_min(weights) <= 0) { + if (weights && ecount > 0 && igraph_vector_min(weights) <= 0) { IGRAPH_ERROR("Weights must be positive for Fruchterman-Reingold layout.", IGRAPH_EINVAL); } - if (minx && igraph_vector_size(minx) != no_nodes) { + if (minx && igraph_vector_size(minx) != vcount) { IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL); } - if (maxx && igraph_vector_size(maxx) != no_nodes) { + if (maxx && igraph_vector_size(maxx) != vcount) { 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) { + if (miny && igraph_vector_size(miny) != vcount) { IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL); } - if (maxy && igraph_vector_size(maxy) != no_nodes) { + if (maxy && igraph_vector_size(maxy) != vcount) { 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) { + if (minz && igraph_vector_size(minz) != vcount) { IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL); } - if (maxz && igraph_vector_size(maxz) != no_nodes) { + if (maxz && igraph_vector_size(maxz) != vcount) { IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL); } if (minz && maxz && !igraph_vector_all_le(minz, maxz)) { @@ -549,21 +539,19 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, IGRAPH_CHECK(igraph_is_connected(graph, &conn, IGRAPH_WEAK)); if (!conn) { - C = no_nodes * sqrt(no_nodes); + C = vcount * sqrt(vcount); } if (!use_seed) { igraph_i_layout_random_bounded_3d(graph, res, minx, maxx, miny, maxy, minz, maxz); } - IGRAPH_VECTOR_INIT_FINALLY(&dispx, no_nodes); - IGRAPH_VECTOR_INIT_FINALLY(&dispy, no_nodes); - IGRAPH_VECTOR_INIT_FINALLY(&dispz, no_nodes); + IGRAPH_VECTOR_INIT_FINALLY(&dispx, vcount); + IGRAPH_VECTOR_INIT_FINALLY(&dispy, vcount); + IGRAPH_VECTOR_INIT_FINALLY(&dispz, vcount); RNG_BEGIN(); - for (i = 0; i < niter; i++) { - igraph_integer_t v, u, e; - + for (igraph_integer_t i = 0; i < niter; i++) { IGRAPH_ALLOW_INTERRUPTION(); /* calculate repulsive forces, we have a special version @@ -572,8 +560,8 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, igraph_vector_null(&dispy); igraph_vector_null(&dispz); if (conn) { - for (v = 0; v < no_nodes; v++) { - for (u = v + 1; u < no_nodes; u++) { + for (igraph_integer_t v = 0; v < vcount; v++) { + for (igraph_integer_t u = v + 1; u < vcount; u++) { 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); @@ -595,8 +583,8 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, } } } else { - for (v = 0; v < no_nodes; v++) { - for (u = v + 1; u < no_nodes; u++) { + for (igraph_integer_t v = 0; v < vcount; v++) { + for (igraph_integer_t u = v + 1; u < vcount; u++) { 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); @@ -623,7 +611,7 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, } /* calculate attractive forces */ - for (e = 0; e < no_edges; e++) { + for (igraph_integer_t e = 0; e < ecount; 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); @@ -642,7 +630,7 @@ igraph_error_t igraph_layout_fruchterman_reingold_3d(const igraph_t *graph, /* limit max displacement to temperature t and prevent from displacement outside frame */ - for (v = 0; v < no_nodes; v++) { + for (igraph_integer_t v = 0; v < vcount; v++) { igraph_real_t dx = VECTOR(dispx)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t dy = VECTOR(dispy)[v] + RNG_UNIF(-1e-9, 1e-9); igraph_real_t dz = VECTOR(dispz)[v] + RNG_UNIF(-1e-9, 1e-9); diff --git a/src/vendor/cigraph/src/layout/kamada_kawai.c b/src/vendor/cigraph/src/layout/kamada_kawai.c index 59f52cb0bf..26a377acf2 100644 --- a/src/vendor/cigraph/src/layout/kamada_kawai.c +++ b/src/vendor/cigraph/src/layout/kamada_kawai.c @@ -1,8 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* IGraph library. - Copyright (C) 2003-2020 The igraph development team + Copyright (C) 2003-2024 The igraph development 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 @@ -15,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_layout.h" @@ -110,13 +105,13 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t 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_integer_t vcount = igraph_vcount(graph); + igraph_integer_t ecount = igraph_ecount(graph); + igraph_real_t L, L0 = sqrt(vcount); igraph_matrix_t dij, lij, kij; igraph_real_t max_dij; igraph_vector_t D1, D2; - igraph_integer_t i, j, m; + igraph_integer_t m; if (maxiter < 0) { IGRAPH_ERROR("Number of iterations must be non-negative in " @@ -127,31 +122,31 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t IGRAPH_EINVAL); } - if (use_seed && (igraph_matrix_nrow(res) != no_nodes || + if (use_seed && (igraph_matrix_nrow(res) != vcount || 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) { + if (weights && igraph_vector_size(weights) != ecount) { IGRAPH_ERROR("Invalid weight vector length.", IGRAPH_EINVAL); } - if (weights && no_edges > 0 && igraph_vector_min(weights) <= 0) { + if (weights && ecount > 0 && igraph_vector_min(weights) <= 0) { IGRAPH_ERROR("Weights must be positive for Kamada-Kawai layout.", IGRAPH_EINVAL); } - if (minx && igraph_vector_size(minx) != no_nodes) { + if (minx && igraph_vector_size(minx) != vcount) { IGRAPH_ERROR("Invalid minx vector length.", IGRAPH_EINVAL); } - if (maxx && igraph_vector_size(maxx) != no_nodes) { + if (maxx && igraph_vector_size(maxx) != vcount) { 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) { + if (miny && igraph_vector_size(miny) != vcount) { IGRAPH_ERROR("Invalid miny vector length.", IGRAPH_EINVAL); } - if (maxy && igraph_vector_size(maxy) != no_nodes) { + if (maxy && igraph_vector_size(maxy) != vcount) { IGRAPH_ERROR("Invalid maxy vector length.", IGRAPH_EINVAL); } if (miny && maxy && !igraph_vector_all_le(miny, maxy)) { @@ -171,21 +166,21 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t } } - if (no_nodes <= 1) { + if (vcount <= 1) { return IGRAPH_SUCCESS; } - 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_MATRIX_INIT_FINALLY(&dij, vcount, vcount); + IGRAPH_MATRIX_INIT_FINALLY(&kij, vcount, vcount); + IGRAPH_MATRIX_INIT_FINALLY(&lij, vcount, vcount); IGRAPH_CHECK(igraph_distances_dijkstra(graph, &dij, igraph_vss_all(), igraph_vss_all(), weights, IGRAPH_ALL)); /* Find largest finite distance */ max_dij = 0.0; - for (i = 0; i < no_nodes; i++) { - for (j = i + 1; j < no_nodes; j++) { + for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_integer_t j = i + 1; j < vcount; j++) { if (!isfinite(MATRIX(dij, i, j))) { continue; } @@ -197,8 +192,8 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Replace infinite distances by the largest finite distance, * effectively making the graph connected. */ - for (i = 0; i < no_nodes; i++) { - for (j = 0; j < no_nodes; j++) { + for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_integer_t j = 0; j < vcount; j++) { if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; } @@ -206,8 +201,8 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t } L = L0 / max_dij; - for (i = 0; i < no_nodes; i++) { - for (j = 0; j < no_nodes; j++) { + for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_integer_t j = 0; j < vcount; j++) { igraph_real_t tmp = MATRIX(dij, i, j) * MATRIX(dij, i, j); if (i == j) { continue; @@ -218,11 +213,11 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t } /* Initialize delta */ - IGRAPH_VECTOR_INIT_FINALLY(&D1, no_nodes); - IGRAPH_VECTOR_INIT_FINALLY(&D2, no_nodes); - for (m = 0; m < no_nodes; m++) { + IGRAPH_VECTOR_INIT_FINALLY(&D1, vcount); + IGRAPH_VECTOR_INIT_FINALLY(&D2, vcount); + for (m = 0; m < vcount; m++) { igraph_real_t myD1 = 0.0, myD2 = 0.0; - for (i = 0; i < no_nodes; i++) { + for (igraph_integer_t i = 0; i < vcount; i++) { igraph_real_t dx, dy, mi_dist; if (i == m) { continue; @@ -237,7 +232,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t VECTOR(D2)[m] = myD2; } - for (j = 0; j < maxiter; j++) { + for (igraph_integer_t 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; @@ -248,7 +243,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Select maximal delta */ m = 0; max_delta = -1; - for (i = 0; i < no_nodes; i++) { + for (igraph_integer_t i = 0; i < vcount; i++) { igraph_real_t delta = (VECTOR(D1)[i] * VECTOR(D1)[i] + VECTOR(D2)[i] * VECTOR(D2)[i]); if (delta > max_delta) { @@ -262,7 +257,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t old_y = MATRIX(*res, m, 1); /* Calculate D1 and D2, A, B, C */ - for (i = 0; i < no_nodes; i++) { + for (igraph_integer_t i = 0; i < vcount; i++) { igraph_real_t dx, dy, dist, den; if (i == m) { continue; @@ -317,7 +312,7 @@ igraph_error_t igraph_layout_kamada_kawai(const igraph_t *graph, igraph_matrix_t /* Update delta, only with/for the affected node */ VECTOR(D1)[m] = VECTOR(D2)[m] = 0.0; - for (i = 0; i < no_nodes; i++) { + for (igraph_integer_t i = 0; i < vcount; i++) { igraph_real_t old_dx, old_dy, new_dx, new_dy, new_mi_dist, old_mi_dist; if (i == m) { continue; @@ -421,13 +416,13 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri const igraph_vector_t *miny, const igraph_vector_t *maxy, const igraph_vector_t *minz, const igraph_vector_t *maxz) { - const igraph_integer_t no_nodes = igraph_vcount(graph); - const igraph_integer_t no_edges = igraph_ecount(graph); - igraph_real_t L, L0 = sqrt(no_nodes); + const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_integer_t ecount = igraph_ecount(graph); + igraph_real_t L, L0 = sqrt(vcount); igraph_matrix_t dij, lij, kij; igraph_real_t max_dij; igraph_vector_t D1, D2, D3; - igraph_integer_t i, j, m; + igraph_integer_t m; if (maxiter < 0) { IGRAPH_ERROR("Number of iterations must be non-negatice in " @@ -438,40 +433,40 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri IGRAPH_EINVAL); } - if (use_seed && (igraph_matrix_nrow(res) != no_nodes || + if (use_seed && (igraph_matrix_nrow(res) != vcount || 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) { + if (weights && igraph_vector_size(weights) != ecount) { IGRAPH_ERROR("Invalid weight vector length", IGRAPH_EINVAL); } - if (weights && no_edges > 0 && igraph_vector_min(weights) <= 0) { + if (weights && ecount > 0 && igraph_vector_min(weights) <= 0) { IGRAPH_ERROR("Weights must be positive for Kamada-Kawai layout.", IGRAPH_EINVAL); } - if (minx && igraph_vector_size(minx) != no_nodes) { + if (minx && igraph_vector_size(minx) != vcount) { IGRAPH_ERROR("Invalid minx vector length", IGRAPH_EINVAL); } - if (maxx && igraph_vector_size(maxx) != no_nodes) { + if (maxx && igraph_vector_size(maxx) != vcount) { 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) { + if (miny && igraph_vector_size(miny) != vcount) { IGRAPH_ERROR("Invalid miny vector length", IGRAPH_EINVAL); } - if (maxy && igraph_vector_size(maxy) != no_nodes) { + if (maxy && igraph_vector_size(maxy) != vcount) { 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) { + if (minz && igraph_vector_size(minz) != vcount) { IGRAPH_ERROR("Invalid minz vector length", IGRAPH_EINVAL); } - if (maxz && igraph_vector_size(maxz) != no_nodes) { + if (maxz && igraph_vector_size(maxz) != vcount) { IGRAPH_ERROR("Invalid maxz vector length", IGRAPH_EINVAL); } if (minz && maxz && !igraph_vector_all_le(minz, maxz)) { @@ -490,19 +485,19 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri } } - if (no_nodes <= 1) { + if (vcount <= 1) { return IGRAPH_SUCCESS; } - 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_MATRIX_INIT_FINALLY(&dij, vcount, vcount); + IGRAPH_MATRIX_INIT_FINALLY(&kij, vcount, vcount); + IGRAPH_MATRIX_INIT_FINALLY(&lij, vcount, vcount); IGRAPH_CHECK(igraph_distances_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++) { + for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_integer_t j = i + 1; j < vcount; j++) { if (!isfinite(MATRIX(dij, i, j))) { continue; } @@ -511,8 +506,8 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri } } } - for (i = 0; i < no_nodes; i++) { - for (j = 0; j < no_nodes; j++) { + for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_integer_t j = 0; j < vcount; j++) { if (MATRIX(dij, i, j) > max_dij) { MATRIX(dij, i, j) = max_dij; } @@ -520,8 +515,8 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri } L = L0 / max_dij; - for (i = 0; i < no_nodes; i++) { - for (j = 0; j < no_nodes; j++) { + for (igraph_integer_t i = 0; i < vcount; i++) { + for (igraph_integer_t j = 0; j < vcount; j++) { igraph_real_t tmp = MATRIX(dij, i, j) * MATRIX(dij, i, j); if (i == j) { continue; @@ -532,13 +527,13 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri } /* 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_VECTOR_INIT_FINALLY(&D1, vcount); + IGRAPH_VECTOR_INIT_FINALLY(&D2, vcount); + IGRAPH_VECTOR_INIT_FINALLY(&D3, vcount); + for (m = 0; m < vcount; 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++) { + for (igraph_integer_t i = 0; i < vcount; i++) { if (i == m) { continue; } @@ -555,7 +550,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri VECTOR(D3)[m] = myD3; } - for (j = 0; j < maxiter; j++) { + for (igraph_integer_t 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; @@ -566,7 +561,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri /* Select maximal delta */ m = 0; max_delta = -1; - for (i = 0; i < no_nodes; i++) { + for (igraph_integer_t i = 0; i < vcount; i++) { igraph_real_t delta = (VECTOR(D1)[i] * VECTOR(D1)[i] + VECTOR(D2)[i] * VECTOR(D2)[i] + VECTOR(D3)[i] * VECTOR(D3)[i]); @@ -582,7 +577,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri old_z = MATRIX(*res, m, 2); /* Calculate D1, D2 and D3, and other coefficients */ - for (i = 0; i < no_nodes; i++) { + for (igraph_integer_t i = 0; i < vcount; i++) { igraph_real_t dx, dy, dz, dist, den, k_mi, l_mi; if (i == m) { continue; @@ -646,7 +641,7 @@ igraph_error_t igraph_layout_kamada_kawai_3d(const igraph_t *graph, igraph_matri /* 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++) { + for (igraph_integer_t i = 0; i < vcount; 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; diff --git a/src/vendor/cigraph/src/layout/merge_grid.c b/src/vendor/cigraph/src/layout/merge_grid.c index 38e36d54f1..a037a111a8 100644 --- a/src/vendor/cigraph/src/layout/merge_grid.c +++ b/src/vendor/cigraph/src/layout/merge_grid.c @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* - IGraph package. - Copyright (C) 2006-2021 The igraph development team + IGraph library. + Copyright (C) 2006-2024 The igraph development 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 @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "layout/merge_grid.h" @@ -205,14 +201,3 @@ igraph_integer_t igraph_i_layout_mergegrid_get_sphere(igraph_i_layout_mergegrid_ return ret; } - -/* int print_grid(igraph_i_layout_mergegrid_t *grid) { */ -/* igraph_integer_t i,j; */ - -/* for (i=0; istepsx; i++) { */ -/* for (j=0; jstepsy; j++) { */ -/* printf("%li ", MAT(i,j)-1); */ -/* } */ -/* printf("\n"); */ -/* } */ -/* } */ diff --git a/src/vendor/cigraph/src/layout/merge_grid.h b/src/vendor/cigraph/src/layout/merge_grid.h index 82c65184a9..c4dd0f2c76 100644 --- a/src/vendor/cigraph/src/layout/merge_grid.h +++ b/src/vendor/cigraph/src/layout/merge_grid.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* IGraph library. - Copyright (C) 2009-2020 The igraph development team + Copyright (C) 2009-2020 The igraph development 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 @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_LAYOUT_MERGE_GRID_H diff --git a/src/vendor/cigraph/src/layout/reingold_tilford.c b/src/vendor/cigraph/src/layout/reingold_tilford.c index 607368e152..0ec727713c 100644 --- a/src/vendor/cigraph/src/layout/reingold_tilford.c +++ b/src/vendor/cigraph/src/layout/reingold_tilford.c @@ -573,7 +573,7 @@ igraph_error_t igraph_roots_for_tree_layout( IGRAPH_VECTOR_INIT_FINALLY(&ecc, no_of_nodes); IGRAPH_CHECK(igraph_eccentricity(graph, &ecc, igraph_vss_all(), mode)); - IGRAPH_CHECK(igraph_vector_qsort_ind(&ecc, &order, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_sort_ind(&ecc, &order, IGRAPH_ASCENDING)); igraph_vector_destroy(&ecc); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/layout/sugiyama.c b/src/vendor/cigraph/src/layout/sugiyama.c index 0107bf29d6..6db8794649 100644 --- a/src/vendor/cigraph/src/layout/sugiyama.c +++ b/src/vendor/cigraph/src/layout/sugiyama.c @@ -37,8 +37,6 @@ #include "internal/glpk_support.h" #include "misc/feedback_arc_set.h" -#include "config.h" - #include /* #define SUGIYAMA_DEBUG */ @@ -344,7 +342,7 @@ igraph_error_t igraph_layout_sugiyama(const igraph_t *graph, igraph_matrix_t *re if (no_of_nodes > 0) { igraph_vector_int_t inds; IGRAPH_VECTOR_INT_INIT_FINALLY(&inds, 0); - IGRAPH_CHECK(igraph_vector_int_qsort_ind(&layers_own, &inds, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_int_sort_ind(&layers_own, &inds, IGRAPH_ASCENDING)); j = -1; dx = VECTOR(layers_own)[VECTOR(inds)[0]] - 1; for (i = 0; i < no_of_nodes; i++) { k = VECTOR(inds)[i]; @@ -791,7 +789,7 @@ static igraph_error_t igraph_i_layout_sugiyama_order_nodes_horizontally(const ig printf("Vertices: "); igraph_vector_int_print(layer_members); printf("Barycenters: "); igraph_vector_print(&barycenters); #endif - IGRAPH_CHECK(igraph_vector_qsort_ind(&barycenters, &sort_indices, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_sort_ind(&barycenters, &sort_indices, IGRAPH_ASCENDING)); for (i = 0; i < n; i++) { nei = VECTOR(*layer_members)[VECTOR(sort_indices)[i]]; VECTOR(new_layer_members)[i] = nei; @@ -825,7 +823,7 @@ static igraph_error_t igraph_i_layout_sugiyama_order_nodes_horizontally(const ig printf("Barycenters: "); igraph_vector_print(&barycenters); #endif - IGRAPH_CHECK(igraph_vector_qsort_ind(&barycenters, &sort_indices, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_sort_ind(&barycenters, &sort_indices, IGRAPH_ASCENDING)); for (i = 0; i < n; i++) { nei = VECTOR(*layer_members)[VECTOR(sort_indices)[i]]; VECTOR(new_layer_members)[i] = nei; @@ -1140,7 +1138,7 @@ static igraph_error_t igraph_i_layout_sugiyama_vertical_alignment(const igraph_t for (k = 0; k < n; k++) { VECTOR(xs)[k] = X_POS(VECTOR(neis)[k]); } - IGRAPH_CHECK(igraph_vector_qsort_ind(&xs, &inds, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_sort_ind(&xs, &inds, IGRAPH_ASCENDING)); if (n % 2 == 1) { /* Odd number of neighbors, so the median is unique */ diff --git a/src/vendor/cigraph/src/layout/umap.c b/src/vendor/cigraph/src/layout/umap.c index 65c969d4ed..256dffc0a1 100644 --- a/src/vendor/cigraph/src/layout/umap.c +++ b/src/vendor/cigraph/src/layout/umap.c @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* IGraph library. - Copyright (C) 2008-2021 The igraph development team + Copyright (C) 2022-2024 The igraph development 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 @@ -15,7 +14,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . - */ +*/ #include "igraph_layout.h" @@ -222,7 +221,7 @@ igraph_error_t igraph_layout_umap_compute_weights( igraph_integer_t no_of_vertices = igraph_vcount(graph); igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_neis, eid, i, j, k, l; + igraph_integer_t no_of_neis; igraph_vector_int_t eids; igraph_vector_int_list_t neighbors_seen; igraph_vector_list_t weights_seen; @@ -254,7 +253,7 @@ igraph_error_t igraph_layout_umap_compute_weights( IGRAPH_VECTOR_LIST_INIT_FINALLY(&weights_seen, no_of_vertices); /* Iterate over vertices x, like in the paper */ - for (i = 0; i < no_of_vertices; i++) { + for (igraph_integer_t i = 0; i < no_of_vertices; i++) { /* Edges out of this vertex, e.g. to its k-nearest neighbors */ IGRAPH_CHECK(igraph_incident(graph, &eids, i, IGRAPH_OUT)); no_of_neis = igraph_vector_int_size(&eids); @@ -268,8 +267,8 @@ igraph_error_t igraph_layout_umap_compute_weights( if (distances != NULL) { rho = VECTOR(*distances)[VECTOR(eids)[0]]; dist_max = rho; - for (j = 1; j < no_of_neis; j++) { - eid = VECTOR(eids)[j]; + for (igraph_integer_t j = 1; j < no_of_neis; j++) { + const igraph_integer_t eid = VECTOR(eids)[j]; dist = VECTOR(*distances)[eid]; rho = fmin(rho, dist); dist_max = fmax(dist_max, dist); @@ -293,8 +292,8 @@ igraph_error_t igraph_layout_umap_compute_weights( } /* Convert to weights */ - for (j = 0; j < no_of_neis; j++) { - eid = VECTOR(eids)[j]; + for (igraph_integer_t j = 0; j < no_of_neis; j++) { + const igraph_integer_t eid = VECTOR(eids)[j]; /* Basically, nodes closer than rho have probability 1, the rest is * exponentially penalized keeping rough cardinality */ @@ -307,7 +306,7 @@ igraph_error_t igraph_layout_umap_compute_weights( #endif /* Store in vector lists for later symmetrization */ - k = IGRAPH_OTHER(graph, eid, i); + const igraph_integer_t k = IGRAPH_OTHER(graph, eid, i); if (k == i) { IGRAPH_ERROR("Input graph must contain no self-loops.", IGRAPH_EINVAL); } @@ -324,9 +323,9 @@ igraph_error_t igraph_layout_umap_compute_weights( /* Symmetrize the weights. UMAP weights are probabilities of that edge being a * "real" connection. Unlike the distances, which can represent a directed graph, * weights are usually symmetric. We symmetrize via fuzzy union. */ - for (eid=0; eid < no_of_edges; eid++) { - i = IGRAPH_FROM(graph, eid); - k = IGRAPH_TO(graph, eid); + for (igraph_integer_t eid=0; eid < no_of_edges; eid++) { + const igraph_integer_t i = IGRAPH_FROM(graph, eid); + const igraph_integer_t k = IGRAPH_TO(graph, eid); /* Direct weight, if found */ /* NOTE: this and the subsequent loop could be faster if we sorted the vectors @@ -335,7 +334,7 @@ igraph_error_t igraph_layout_umap_compute_weights( neighbors_seen_elt = igraph_vector_int_list_get_ptr(&neighbors_seen, i); weights_seen_elt = igraph_vector_list_get_ptr(&weights_seen, i); no_of_neis = igraph_vector_int_size(neighbors_seen_elt); - for (l=0; l < no_of_neis; l++) { + for (igraph_integer_t l=0; l < no_of_neis; l++) { if (VECTOR(*neighbors_seen_elt)[l] == k) { weight = VECTOR(*weights_seen_elt)[l]; /* Tag this weight so we can ignore it later on if the opposite @@ -356,7 +355,7 @@ igraph_error_t igraph_layout_umap_compute_weights( neighbors_seen_elt = igraph_vector_int_list_get_ptr(&neighbors_seen, k); weights_seen_elt = igraph_vector_list_get_ptr(&weights_seen, k); no_of_neis = igraph_vector_int_size(neighbors_seen_elt); - for (l=0; l < no_of_neis; l++) { + for (igraph_integer_t l=0; l < no_of_neis; l++) { if (VECTOR(*neighbors_seen_elt)[l] == i) { weight_inv = VECTOR(*weights_seen_elt)[l]; /* Tag this weight so we can ignore it later on if the opposite @@ -572,7 +571,7 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, } } /* LAPACK puts solution into jTr */ - IGRAPH_CHECK(igraph_lapack_dgesv(&jTj, 0, &jTr, &lapack_info)); + IGRAPH_CHECK(igraph_lapack_dgesv(&jTj, NULL, &jTr, &lapack_info)); /* This might go wrong, in which case we should fail graciously */ if (lapack_info != 0) { @@ -603,7 +602,7 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, /* Compare and if we are going back uphill, undo last step and break */ #ifdef UMAP_DEBUG - printf("during line search, k = %d, old SSR:, %g, new SSR (half a,b):, %g\n", k, + printf("during line search, k = %" IGRAPH_PRId ", old SSR:, %g, new SSR (half a,b):, %g\n", k, squared_sum_res_tmp, squared_sum_res); #endif if (squared_sum_res > squared_sum_res_tmp - tol) { @@ -623,12 +622,12 @@ igraph_error_t igraph_i_umap_fit_ab(igraph_real_t min_dist, igraph_real_t *a_p, } /* Free memory and tidy up stack */ - igraph_vector_destroy(&x); - igraph_vector_destroy(&residuals); - igraph_matrix_destroy(&jacobian); - igraph_matrix_destroy(&jTj); - igraph_matrix_destroy(&jTr); igraph_vector_destroy(&powb); + igraph_matrix_destroy(&jTr); + igraph_matrix_destroy(&jTj); + igraph_matrix_destroy(&jacobian); + igraph_vector_destroy(&residuals); + igraph_vector_destroy(&x); IGRAPH_FINALLY_CLEAN(6); #ifdef UMAP_DEBUG @@ -717,11 +716,11 @@ static igraph_error_t igraph_i_umap_compute_cross_entropy(const igraph_t *graph, /* clip forces to avoid too rapid shifts */ -static igraph_real_t igraph_i_umap_clip_force(igraph_real_t force, igraph_real_t limit) { +static IGRAPH_FUNCATTR_CONST igraph_real_t igraph_i_umap_clip_force(igraph_real_t force, igraph_real_t limit) { return force > limit ? limit : (force < -limit ? -limit : force); } -static igraph_real_t igraph_i_umap_attract( +static IGRAPH_FUNCATTR_CONST igraph_real_t igraph_i_umap_attract( igraph_real_t dsq, igraph_real_t a, igraph_real_t b) @@ -729,7 +728,7 @@ static igraph_real_t igraph_i_umap_attract( return - (2 * a * b * pow(dsq, b - 1.)) / (1. + a * pow(dsq, b)); } -static igraph_real_t igraph_i_umap_repel( +static IGRAPH_FUNCATTR_CONST igraph_real_t igraph_i_umap_repel( igraph_real_t dsq, igraph_real_t a, igraph_real_t b) @@ -751,31 +750,32 @@ static igraph_error_t igraph_i_umap_apply_forces( igraph_integer_t epoch, igraph_vector_t *next_epoch_sample_per_edge) { - igraph_integer_t no_of_vertices = igraph_matrix_nrow(layout); - igraph_integer_t ndim = igraph_matrix_ncol(layout); - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t from, to, nneis, eid; + const igraph_integer_t no_of_vertices = igraph_matrix_nrow(layout); + const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_integer_t ndim = igraph_matrix_ncol(layout); igraph_vector_t from_emb, to_emb, delta; - igraph_real_t force = 0, dsq, force_d; + /* The following is only used for small graphs, to avoid repelling your neighbors * For large sparse graphs, it's not necessary. For large dense graphs, you should - * not be doing UMAP. - * */ + * not be doing UMAP. */ igraph_vector_int_t neis, negative_vertices; - igraph_integer_t n_negative_vertices = (no_of_vertices - 1 < negative_sampling_rate) ? (no_of_vertices - 1) : negative_sampling_rate; + const igraph_integer_t n_negative_vertices = + (no_of_vertices - 1 < negative_sampling_rate) ? (no_of_vertices - 1) : negative_sampling_rate; /* Initialize vectors */ IGRAPH_VECTOR_INIT_FINALLY(&from_emb, ndim); IGRAPH_VECTOR_INIT_FINALLY(&to_emb, ndim); IGRAPH_VECTOR_INIT_FINALLY(&delta, ndim); - + IGRAPH_VECTOR_INT_INIT_FINALLY(&negative_vertices, 0); if (avoid_neighbor_repulsion) { IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); } - IGRAPH_VECTOR_INT_INIT_FINALLY(&negative_vertices, 0); /* Iterate over edges. Stronger edges are sampled more often */ - for (eid = 0; eid < no_of_edges; eid++) { + for (igraph_integer_t eid = 0; eid < no_of_edges; eid++) { + igraph_integer_t from, to; + igraph_real_t force, dsq, force_d; + /* Zero-weight edges do not affect vertex positions. They can * also emerge during the weight symmetrization. */ if (VECTOR(*umap_weights)[eid] <= 0) { @@ -827,7 +827,7 @@ static igraph_error_t igraph_i_umap_apply_forces( force_d = igraph_i_umap_clip_force(force_d, UMAP_FORCE_LIMIT); #ifdef UMAP_DEBUG - fprintf(stderr, "force attractive: delta[%ld] = %g, forces[%ld] = %g\n", d, VECTOR(delta)[d], d, force_d); + fprintf(stderr, "force attractive: delta[%" IGRAPH_PRId "] = %g, forces[%" IGRAPH_PRId "] = %g\n", d, VECTOR(delta)[d], d, force_d); #endif MATRIX(*layout, from, d) += learning_rate * force_d; @@ -853,20 +853,20 @@ static igraph_error_t igraph_i_umap_apply_forces( if (avoid_neighbor_repulsion) { /* NOTE: the efficiency of this step could be improved but it * should be only used for small graphs anyway, so it's fine */ - igraph_bool_t skip = 0; + igraph_bool_t skip = false; IGRAPH_CHECK(igraph_incident(graph, &neis, from, IGRAPH_ALL)); - nneis = igraph_vector_int_size(&neis); + const igraph_integer_t nneis = igraph_vector_int_size(&neis); for (igraph_integer_t k = 0; k < nneis; k++) { igraph_integer_t eid2 = VECTOR(neis)[k]; igraph_integer_t from2, to2; from2 = IGRAPH_FROM(graph, eid2); to2 = IGRAPH_TO(graph, eid2); if (((from2 == from) && (to2 == to)) || ((from2 == to) && (from == to2))) { - skip = 1; + skip = true; break; } } - if (skip == 1) { + if (skip) { continue; } } @@ -890,7 +890,7 @@ static igraph_error_t igraph_i_umap_apply_forces( force_d = igraph_i_umap_clip_force(force_d, UMAP_FORCE_LIMIT); #ifdef UMAP_DEBUG - fprintf(stderr, "force repulsive: delta[%ld] = %g, forces[%ld] = %g\n", d, VECTOR(delta)[d], d, force_d); + fprintf(stderr, "force repulsive: delta[%" IGRAPH_PRId "] = %g, forces[%" IGRAPH_PRId "] = %g\n", d, VECTOR(delta)[d], d, force_d); #endif MATRIX(*layout, from, d) += learning_rate * force_d; @@ -899,19 +899,19 @@ static igraph_error_t igraph_i_umap_apply_forces( } } - /* Free vectors */ - igraph_vector_int_destroy(&negative_vertices); - igraph_vector_destroy(&from_emb); - igraph_vector_destroy(&to_emb); - igraph_vector_destroy(&delta); - IGRAPH_FINALLY_CLEAN(4); - /* Free vector of neighbors if needed */ if (avoid_neighbor_repulsion) { igraph_vector_int_destroy(&neis); IGRAPH_FINALLY_CLEAN(1); } + /* Free vectors */ + igraph_vector_int_destroy(&negative_vertices); + igraph_vector_destroy(&delta); + igraph_vector_destroy(&to_emb); + igraph_vector_destroy(&from_emb); + IGRAPH_FINALLY_CLEAN(4); + return IGRAPH_SUCCESS; } @@ -944,9 +944,9 @@ static igraph_error_t igraph_i_umap_optimize_layout_stochastic_gradient( * relies on an approximation that only works if the graph is sparse, which is never * quite true for small graphs (i.e. |V| << |E| << |V|^2 is hard to judge if * |V| is small) */ - igraph_bool_t avoid_neighbor_repulsion = 0; + igraph_bool_t avoid_neighbor_repulsion = false; if (igraph_vcount(graph) < 100) { - avoid_neighbor_repulsion = 1; + avoid_neighbor_repulsion = true; } /* Measure the (variable part of the) cross-entropy terms for debugging: @@ -959,13 +959,13 @@ static igraph_error_t igraph_i_umap_optimize_layout_stochastic_gradient( * function Phi. * */ #ifdef UMAP_DEBUG - igraph_umap_compute_cross_entropy( + igraph_i_umap_compute_cross_entropy( graph, umap_weights, layout, a, b, &cross_entropy); #endif for (igraph_integer_t e = 0; e < epochs; e++) { /* Apply (stochastic) forces */ - igraph_i_umap_apply_forces( + IGRAPH_CHECK(igraph_i_umap_apply_forces( graph, umap_weights, layout, @@ -974,12 +974,12 @@ static igraph_error_t igraph_i_umap_optimize_layout_stochastic_gradient( avoid_neighbor_repulsion, negative_sampling_rate, e, - &next_epoch_sample_per_edge); + &next_epoch_sample_per_edge)); #ifdef UMAP_DEBUG /* Recompute CE and check how it's going*/ cross_entropy_old = cross_entropy; - igraph_umap_compute_cross_entropy( + igraph_i_umap_compute_cross_entropy( graph, umap_weights, layout, a, b, &cross_entropy); printf("Cross-entropy before shift: %g, after shift: %g\n", cross_entropy_old, cross_entropy); @@ -995,14 +995,12 @@ static igraph_error_t igraph_i_umap_optimize_layout_stochastic_gradient( return IGRAPH_SUCCESS; } -/* Center layout around (0,0) at the end, just for convenience */ -static igraph_error_t igraph_i_umap_center_layout(igraph_matrix_t *layout) { +/* Center 2D layout around (0,0) at the end, just for convenience */ +static void igraph_i_umap_center_layout(igraph_matrix_t *layout) { igraph_integer_t no_of_vertices = igraph_matrix_nrow(layout); igraph_real_t xm = 0, ym = 0; /* Compute center */ - xm = 0; - ym = 0; for (igraph_integer_t i = 0; i < no_of_vertices; i++) { xm += MATRIX(*layout, i, 0); ym += MATRIX(*layout, i, 1); @@ -1015,8 +1013,29 @@ static igraph_error_t igraph_i_umap_center_layout(igraph_matrix_t *layout) { MATRIX(*layout, i, 0) -= xm; MATRIX(*layout, i, 1) -= ym; } +} - return IGRAPH_SUCCESS; +/* Center 3D layout around (0,0,0) at the end, just for convenience */ +static void igraph_i_umap_center_layout_3d(igraph_matrix_t *layout) { + igraph_integer_t no_of_vertices = igraph_matrix_nrow(layout); + igraph_real_t xm = 0, ym = 0, zm = 0; + + /* Compute center */ + for (igraph_integer_t i = 0; i < no_of_vertices; i++) { + xm += MATRIX(*layout, i, 0); + ym += MATRIX(*layout, i, 1); + zm += MATRIX(*layout, i, 2); + } + xm /= no_of_vertices; + ym /= no_of_vertices; + zm /= no_of_vertices; + + /* Shift vertices */ + for (igraph_integer_t i = 0; i < no_of_vertices; i++) { + MATRIX(*layout, i, 0) -= xm; + MATRIX(*layout, i, 1) -= ym; + MATRIX(*layout, i, 2) -= zm; + } } @@ -1032,8 +1051,8 @@ static igraph_error_t igraph_i_layout_umap( igraph_integer_t ndim, igraph_bool_t distances_are_weights) { - igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t no_of_vertices = igraph_vcount(graph); + const igraph_integer_t no_of_edges = igraph_ecount(graph); + const igraph_integer_t no_of_vertices = igraph_vcount(graph); /* probabilities of each edge being a real connection */ igraph_vector_t weights; igraph_vector_t *weightsp; @@ -1059,6 +1078,10 @@ static igraph_error_t igraph_i_layout_umap( } + if (distances == NULL) { + distances_are_weights = false; + } + /* Compute weights (exponential weights) from distances if required. * If the weights have already been computed, they are stored in * the "distances" vector and we can recycle the pointer. */ @@ -1131,14 +1154,19 @@ static igraph_error_t igraph_i_layout_umap( epochs, negative_sampling_rate)); + RNG_END(); + if (!distances_are_weights) { igraph_vector_destroy(&weights); IGRAPH_FINALLY_CLEAN(1); } - RNG_END(); /* Center layout */ - IGRAPH_CHECK(igraph_i_umap_center_layout(res)); + if (ndim == 2) { + igraph_i_umap_center_layout(res); + } else { + igraph_i_umap_center_layout_3d(res); + } return IGRAPH_SUCCESS; } diff --git a/src/vendor/cigraph/src/linalg/arpack_internal.h b/src/vendor/cigraph/src/linalg/arpack_internal.h index 8daaaaf79b..0392624d17 100644 --- a/src/vendor/cigraph/src/linalg/arpack_internal.h +++ b/src/vendor/cigraph/src/linalg/arpack_internal.h @@ -29,7 +29,7 @@ */ #include "igraph_decls.h" -#include "config.h" +#include "config.h" /* INTERNAL_ARPACK */ __BEGIN_DECLS diff --git a/src/vendor/cigraph/src/linalg/blas_internal.h b/src/vendor/cigraph/src/linalg/blas_internal.h index 58ff5f8686..ab1bd693c2 100644 --- a/src/vendor/cigraph/src/linalg/blas_internal.h +++ b/src/vendor/cigraph/src/linalg/blas_internal.h @@ -30,7 +30,7 @@ */ #include "igraph_decls.h" -#include "config.h" +#include "config.h" /* INTERNAL_BLAS */ __BEGIN_DECLS diff --git a/src/vendor/cigraph/src/linalg/lapack_internal.h b/src/vendor/cigraph/src/linalg/lapack_internal.h index baef8d29ee..b95885d1b8 100644 --- a/src/vendor/cigraph/src/linalg/lapack_internal.h +++ b/src/vendor/cigraph/src/linalg/lapack_internal.h @@ -30,7 +30,7 @@ */ #include "igraph_decls.h" -#include "config.h" +#include "config.h" /* INTERNAL_LAPACK */ __BEGIN_DECLS diff --git a/src/vendor/cigraph/src/math/safe_intop.h b/src/vendor/cigraph/src/math/safe_intop.h index e690e7041a..79db3ddd9c 100644 --- a/src/vendor/cigraph/src/math/safe_intop.h +++ b/src/vendor/cigraph/src/math/safe_intop.h @@ -25,7 +25,7 @@ #include "igraph_types.h" #include "igraph_vector.h" -#include "config.h" +#include "config.h" /* HAVE_BUILTIN_OVERFLOW */ #include diff --git a/src/vendor/cigraph/src/misc/feedback_arc_set.c b/src/vendor/cigraph/src/misc/feedback_arc_set.c index 9a34b48800..a0e2bae3b7 100644 --- a/src/vendor/cigraph/src/misc/feedback_arc_set.c +++ b/src/vendor/cigraph/src/misc/feedback_arc_set.c @@ -1,9 +1,6 @@ -/* -*- mode: C -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ /* IGraph library. - Copyright (C) 2011-2012 Gabor Csardi - 334 Harvard street, Cambridge, MA 02139 USA + Copyright (C) 2011-2024 The igraph development 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 @@ -16,19 +13,21 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #include "igraph_structural.h" #include "misc/feedback_arc_set.h" +#include "igraph_bitset.h" #include "igraph_components.h" +#include "igraph_cycles.h" #include "igraph_dqueue.h" #include "igraph_interface.h" #include "igraph_memory.h" +#include "igraph_stack.h" +#include "igraph_topology.h" +#include "igraph_vector.h" #include "igraph_vector_list.h" #include "igraph_visitor.h" @@ -37,6 +36,230 @@ #include +/** + * \param found If not NULL, will indicate if any cycles were found. + * \param A bitset the same length as the edge count, indicating which edges + * to consider non-existent. + * + * See igraph_find_cycle() for the other parameters. + * + * \return Error code. + */ +static igraph_error_t igraph_i_find_cycle(const igraph_t *graph, + igraph_vector_int_t *vertices, + igraph_vector_int_t *edges, + igraph_bool_t *found, + igraph_neimode_t mode, + const igraph_bitset_t *removed) { + + const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_integer_t ecount = igraph_ecount(graph); + igraph_stack_int_t stack; + igraph_vector_int_t inc; + igraph_vector_int_t vpath, epath; + igraph_vector_char_t seen; /* 0 = unseen, 1 = acestor of current, 2 = seen, non-ancestor */ + igraph_integer_t ea, va; + igraph_integer_t depth; + + if (vertices) { + igraph_vector_int_clear(vertices); + } + if (edges) { + igraph_vector_int_clear(edges); + } + if (found) { + *found = false; + } + + if (ecount == 0) { + return IGRAPH_SUCCESS; + } + +#define PATH_PUSH(v, e) \ + do { \ + IGRAPH_CHECK(igraph_vector_int_push_back(&epath, e)); \ + IGRAPH_CHECK(igraph_vector_int_push_back(&vpath, v)); \ + VECTOR(seen)[v] = 1; \ + } while (0) + +#define PATH_POP() \ + do { \ + igraph_vector_int_pop_back(&epath); \ + VECTOR(seen)[igraph_vector_int_pop_back(&vpath)] = 2; \ + } while (0) + + IGRAPH_VECTOR_INT_INIT_FINALLY(&vpath, 100); + igraph_vector_int_clear(&vpath); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&epath, 100); + igraph_vector_int_clear(&epath); + + IGRAPH_VECTOR_INT_INIT_FINALLY(&inc, 10); + IGRAPH_VECTOR_CHAR_INIT_FINALLY(&seen, vcount); + IGRAPH_STACK_INT_INIT_FINALLY(&stack, 200); + + for (igraph_integer_t v=0; v < vcount; v++) { + if (VECTOR(seen)[v]) { + continue; + } + + IGRAPH_CHECK(igraph_stack_int_push(&stack, -1)); + IGRAPH_CHECK(igraph_stack_int_push(&stack, v)); + + while (! igraph_stack_int_empty(&stack)) { + igraph_integer_t x = igraph_stack_int_pop(&stack); + if (x == -1) { + PATH_POP(); + continue; + } else { + va = x; + ea = igraph_stack_int_pop(&stack); + + if (VECTOR(seen)[va] == 1) { + goto finish; + } else if (VECTOR(seen)[va] == 2) { + continue; + } + } + + PATH_PUSH(va, ea); + + IGRAPH_CHECK(igraph_stack_int_push(&stack, -1)); + IGRAPH_CHECK(igraph_incident(graph, &inc, va, mode)); + igraph_integer_t n = igraph_vector_int_size(&inc); + for (igraph_integer_t i=0; i < n; i++) { + igraph_integer_t eb = VECTOR(inc)[i]; + igraph_integer_t vb = IGRAPH_OTHER(graph, eb, va); + if (eb == ea) continue; + if (VECTOR(seen)[vb] == 2) continue; + if (removed && IGRAPH_BIT_TEST(*removed, eb)) continue; + IGRAPH_CHECK(igraph_stack_int_push(&stack, eb)); + IGRAPH_CHECK(igraph_stack_int_push(&stack, vb)); + } + } + } + + +finish: + + igraph_stack_int_destroy(&stack); + igraph_vector_char_destroy(&seen); + igraph_vector_int_destroy(&inc); + IGRAPH_FINALLY_CLEAN(3); + + depth = igraph_vector_int_size(&vpath); + + if (depth > 0) { + igraph_integer_t i = depth; + while (VECTOR(vpath)[i-1] != va) i--; + for (; i < depth; i++) { + if (vertices) { + igraph_vector_int_push_back(vertices, VECTOR(vpath)[i]); + } + if (edges) { + igraph_vector_int_push_back(edges, VECTOR(epath)[i]); + } + } + if (vertices) { + igraph_vector_int_push_back(vertices, va); + } + if (edges) { + igraph_vector_int_push_back(edges, ea); + } + if (found) { + *found = true; + } + } + + igraph_vector_int_destroy(&epath); + igraph_vector_int_destroy(&vpath); + IGRAPH_FINALLY_CLEAN(2); + + return IGRAPH_SUCCESS; + +#undef PATH_PUSH +#undef PATH_POP +} + + +/** + * \function igraph_find_cycle + * \brief Finds a single cycle in the graph. + * + * \experimental + * + * This function returns a cycle of the graph, if there is one. If the graph + * is acyclic, it returns empty vectors. + * + * \param graph The input graph. + * \param vertices Pointer to an integer vector. If a cycle is found, its + * vertices will be stored here. Otherwise the vector will be empty. + * \param edges Pointer to an integer vector. If a cycle is found, its + * edges will be stored here. Otherwise the vector will be empty. + * \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|), where |V| and |E| are the number of + * vertices and edges in the original input graph. + * + * \sa \ref igraph_is_acyclic() to determine if a graph is acyclic, + * without returning a specific cycle. + */ +igraph_error_t igraph_find_cycle(const igraph_t *graph, + igraph_vector_int_t *vertices, + igraph_vector_int_t *edges, + igraph_neimode_t mode) { + + /* If the graph is cached to be acyclic, we don't need to run the algorithm. */ + + igraph_bool_t known_acyclic = false; + igraph_bool_t found; + + if (! igraph_is_directed(graph)) { + mode = IGRAPH_ALL; + } + + if (mode == IGRAPH_ALL) /* undirected */ { + if (igraph_i_property_cache_has(graph, IGRAPH_PROP_IS_FOREST) && + igraph_i_property_cache_get_bool(graph, IGRAPH_PROP_IS_FOREST)) { + known_acyclic = true; + } + } else /* directed */ { + if (igraph_i_property_cache_has(graph, IGRAPH_PROP_IS_DAG) && + igraph_i_property_cache_get_bool(graph, IGRAPH_PROP_IS_DAG)) { + known_acyclic = true; + } + } + + if (known_acyclic) { + if (vertices) { + igraph_vector_int_clear(vertices); + } + if (edges) { + igraph_vector_int_clear(edges); + } + return IGRAPH_SUCCESS; + } + + IGRAPH_CHECK(igraph_i_find_cycle(graph, vertices, edges, &found, mode, NULL)); + + if (! found) { + if (mode == IGRAPH_ALL) /* undirected */ { + igraph_i_property_cache_set_bool_checked(graph, IGRAPH_PROP_IS_FOREST, true); + } else /* directed */ { + igraph_i_property_cache_set_bool_checked(graph, IGRAPH_PROP_IS_DAG, true); + } + } + + return IGRAPH_SUCCESS; +} + + /** * \ingroup structural * \function igraph_feedback_arc_set @@ -44,31 +267,69 @@ * * 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. + * whose total weight is the smallest among all the feedback arc sets. * * - * For undirected graphs, the problem is simple: one has to find a maximum weight + * For undirected graphs, the solution 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. + * graphs, this is an NP-complete problem, and various heuristics are usually used to + * find an approximate solution to the problem. This function implements both exact + * methods and heuristics, selectable with the \p algo parameter. + * + * + * References: * - * \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. + * + * Eades P, Lin X and Smyth WF: + * A fast and effective heuristic for the feedback arc set problem. + * Information Processing Letters 47(6), pp 319-323 (1993). + * https://doi.org/10.1016/0020-0190(93)90079-O + * + * + * Baharev A, Hermann S, Arnold N and Tobias A: + * An Exact Method for the Minimum Feedback Arc Set Problem. + * ACM Journal of Experimental Algorithmics 26, 1–28 (2021). + * https://doi.org/10.1145/3446429. + * + * \param graph The graph object. + * \param result An initialized vector, the result will be written here. + * \param weights Weight vector or \c 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. + * Finds a \em minimum feedback arc set using integer programming (IP), + * automatically selecting the best method of this type (currently + * always \c IGRAPH_FAS_EXACT_IP_CG). The complexity is of course + * at least exponential. + * \cli IGRAPH_FAS_EXACT_IP_CG + * This is an integer programming approach based on a minimum set cover + * formulation and using incremental constraint generation (CG), added + * in igraph 0.10.14. We minimize sum_e w_e b_e subject to + * the constraints sum_e c_e b_e >= 1 for all cycles \c c. + * Here \c w_e is the weight of edge \c e, \c b_e is a binary variable + * (0 or 1) indicating whether edge \c e is in the feedback set, + * and \c c_e is a binary coefficient indicating whether edge \c e + * is in cycle \c c. The constraint expresses the requirement that all + * cycles must intersect with (be broken by) the edge set represented + * by \c b. Since there are a very large number of cycles in the graph, + * constraints are generated incrementally, iteratively adding some cycles + * that do not intersect with the current edge set \c b, then solving for + * \c b again, until finally no unbroken cycles remain. This approach is + * similar to that described by Baharev et al (though with a simpler + * cycle generation scheme), and to what is implemented by SageMath's. + * \c feedback_edge_set function. + * \cli IGRAPH_FAS_EXACT_IP_TI + * This is another integer programming approach based on finding a + * maximum (largest weight) edge set that adheres to a topological + * order. It uses the common formulation through triangle inequalities + * (TI), see Section 3.1 of Baharev et al (2021) for an overview. This + * method was used before igraph 0.10.14, and is typically much slower + * than \c IGRAPH_FAS_EXACT_IP_CG. * \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. + * and it is linear in the number of edges (i.e. O(|E|)) to compute. * \endclist * * \return Error code: @@ -80,29 +341,91 @@ * * Time complexity: depends on \p algo, see the time complexities there. */ -igraph_error_t igraph_feedback_arc_set(const igraph_t *graph, igraph_vector_int_t *result, - const igraph_vector_t *weights, igraph_fas_algorithm_t algo) { +igraph_error_t igraph_feedback_arc_set( + const igraph_t *graph, + igraph_vector_int_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 (weights) { + if (igraph_vector_size(weights) != igraph_ecount(graph)) { + IGRAPH_ERROR("Weight vector length must match the number of edges.", IGRAPH_EINVAL); + } + if (! igraph_vector_is_all_finite(weights)) { + IGRAPH_ERROR("Weights must not be infinite or NaN.", IGRAPH_EINVAL); + } + } if (!igraph_is_directed(graph)) { - return igraph_i_feedback_arc_set_undirected(graph, result, weights, 0); + return igraph_i_feedback_arc_set_undirected(graph, result, weights, NULL); } switch (algo) { case IGRAPH_FAS_EXACT_IP: - return igraph_i_feedback_arc_set_ip(graph, result, weights); + case IGRAPH_FAS_EXACT_IP_CG: + return igraph_i_feedback_arc_set_ip_cg(graph, result, weights); + + case IGRAPH_FAS_EXACT_IP_TI: + return igraph_i_feedback_arc_set_ip_ti(graph, result, weights); case IGRAPH_FAS_APPROX_EADES: - return igraph_i_feedback_arc_set_eades(graph, result, weights, 0); + return igraph_i_feedback_arc_set_eades(graph, result, weights, NULL); + + default: + IGRAPH_ERROR("Invalid feedback arc set algorithm.", IGRAPH_EINVAL); + } +} + + +/** + * \function igraph_feedback_vertex_set + * \brief Feedback vertex set of a graph. + * + * \experimental + * + * A feedback vertex set is a set of vertices whose removal makes the graph + * acyclic. Finding a \em minimum feedback vertex set is an NP-complete + * problem, both on directed and undirected graphs. + * + * \param graph The graph. + * \param result An initialized vector, the result will be written here. + * \param vertex_weights Vertex weight vector or \c NULL if no weights are specified. + * \param algo Algorithm to use. Possible values: + * \clist + * \cli IGRAPH_FVS_EXACT_IP + * Finds a \em miniumum feedback vertex set using integer programming + * (IP). The complexity is of course at least exponential. Currently + * this method uses an approach analogous to that of the + * \c IGRAPH_FAS_EXACT_IP_CG algorithm of \ref igraph_feedback_arc_set(). + * \endclist + * + * \return Error code. + * + * Time complexity: depends on \p algo, see the time complexities there. + */ +igraph_error_t igraph_feedback_vertex_set( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *vertex_weights, igraph_fvs_algorithm_t algo) { + + if (vertex_weights) { + if (igraph_vector_size(vertex_weights) != igraph_vcount(graph)) { + IGRAPH_ERROR("Vertex weight vector length must match the number of vertices.", IGRAPH_EINVAL); + } + if (! igraph_vector_is_all_finite(vertex_weights)) { + IGRAPH_ERROR("Vertex weights must not be infinite or NaN.", IGRAPH_EINVAL); + } + } + + switch (algo) { + case IGRAPH_FVS_EXACT_IP: + return igraph_i_feedback_vertex_set_ip_cg(graph, result, vertex_weights); default: - IGRAPH_ERROR("Invalid algorithm", IGRAPH_EINVAL); + IGRAPH_ERROR("Invalid feedback vertex set algorithm.", IGRAPH_EINVAL); } } + /** * Solves the feedback arc set problem for undirected graphs. */ @@ -154,22 +477,22 @@ igraph_error_t igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igrap IGRAPH_VECTOR_INT_INIT_FINALLY(&roots, no_of_nodes); IGRAPH_CHECK(igraph_strength(graph, °rees, igraph_vss_all(), IGRAPH_ALL, /* loops */ false, weights)); - IGRAPH_CHECK(igraph_vector_qsort_ind(°rees, &roots, IGRAPH_DESCENDING)); + IGRAPH_CHECK(igraph_vector_sort_ind(°rees, &roots, IGRAPH_DESCENDING)); IGRAPH_CHECK(igraph_bfs(graph, /* root = */ 0, /* roots = */ &roots, /* mode = */ IGRAPH_OUT, - /* unreachable = */ 0, - /* restricted = */ 0, - /* order = */ 0, - /* rank = */ 0, - /* parents = */ 0, - /* pred = */ 0, - /* succ = */ 0, + /* unreachable = */ false, + /* restricted = */ NULL, + /* order = */ NULL, + /* rank = */ NULL, + /* parents = */ NULL, + /* pred = */ NULL, + /* succ = */ NULL, /* dist = */ layering, - /* callback = */ 0, - /* extra = */ 0)); + /* callback = */ NULL, + /* extra = */ NULL)); igraph_vector_destroy(°rees); igraph_vector_int_destroy(&roots); @@ -182,6 +505,7 @@ igraph_error_t igraph_i_feedback_arc_set_undirected(const igraph_t *graph, igrap return IGRAPH_SUCCESS; } + /** * Solves the feedback arc set problem using the heuristics of Eades et al. */ @@ -189,28 +513,24 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec const igraph_vector_t *weights, igraph_vector_int_t *layers) { const igraph_integer_t no_of_nodes = igraph_vcount(graph); const igraph_integer_t no_of_edges = igraph_ecount(graph); - igraph_integer_t i, j, k, v, eid, nodes_left; + igraph_integer_t nodes_left; + igraph_integer_t neis_size; igraph_dqueue_int_t sources, sinks; igraph_vector_int_t neis; igraph_vector_int_t indegrees, outdegrees; igraph_vector_t instrengths, outstrengths; - igraph_integer_t *ordering; + igraph_vector_int_t ordering; igraph_integer_t order_next_pos = 0, order_next_neg = -1; - igraph_real_t diff, maxdiff; - ordering = IGRAPH_CALLOC(no_of_nodes, igraph_integer_t); - IGRAPH_CHECK_OOM(ordering, "Insufficient memory for finding feedback arc set."); - IGRAPH_FINALLY(igraph_free, ordering); + IGRAPH_VECTOR_INT_INIT_FINALLY(&ordering, no_of_nodes); + IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); + IGRAPH_DQUEUE_INT_INIT_FINALLY(&sources, 0); + IGRAPH_DQUEUE_INT_INIT_FINALLY(&sinks, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&indegrees, no_of_nodes); IGRAPH_VECTOR_INT_INIT_FINALLY(&outdegrees, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&instrengths, no_of_nodes); IGRAPH_VECTOR_INIT_FINALLY(&outstrengths, no_of_nodes); - IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); - IGRAPH_CHECK(igraph_dqueue_int_init(&sources, 0)); - IGRAPH_FINALLY(igraph_dqueue_int_destroy, &sources); - IGRAPH_CHECK(igraph_dqueue_int_init(&sinks, 0)); - IGRAPH_FINALLY(igraph_dqueue_int_destroy, &sinks); IGRAPH_CHECK(igraph_degree(graph, &indegrees, igraph_vss_all(), IGRAPH_IN, false)); IGRAPH_CHECK(igraph_degree(graph, &outdegrees, igraph_vss_all(), IGRAPH_OUT, false)); @@ -219,57 +539,55 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec IGRAPH_CHECK(igraph_strength(graph, &instrengths, igraph_vss_all(), IGRAPH_IN, false, weights)); IGRAPH_CHECK(igraph_strength(graph, &outstrengths, igraph_vss_all(), IGRAPH_OUT, false, weights)); } else { - IGRAPH_CHECK(igraph_vector_resize(&instrengths, no_of_nodes)); - IGRAPH_CHECK(igraph_vector_resize(&outstrengths, no_of_nodes)); - for (igraph_integer_t i = 0; i < no_of_nodes; i++) { - VECTOR(instrengths)[i] = VECTOR(indegrees)[i]; - VECTOR(outstrengths)[i] = VECTOR(outdegrees)[i]; + for (igraph_integer_t u = 0; u < no_of_nodes; u++) { + VECTOR(instrengths)[u] = VECTOR(indegrees)[u]; + VECTOR(outstrengths)[u] = VECTOR(outdegrees)[u]; } } /* 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) { + for (igraph_integer_t u = 0; u < no_of_nodes; u++) { + if (VECTOR(indegrees)[u] == 0) { + if (VECTOR(outdegrees)[u] == 0) { /* Isolated vertex, we simply ignore it */ nodes_left--; - ordering[i] = order_next_pos++; - VECTOR(indegrees)[i] = VECTOR(outdegrees)[i] = -1; + VECTOR(ordering)[u] = order_next_pos++; + VECTOR(indegrees)[u] = VECTOR(outdegrees)[u] = -1; } else { /* This is a source */ - IGRAPH_CHECK(igraph_dqueue_int_push(&sources, i)); + IGRAPH_CHECK(igraph_dqueue_int_push(&sources, u)); } - } else if (VECTOR(outdegrees)[i] == 0) { + } else if (VECTOR(outdegrees)[u] == 0) { /* This is a sink */ - IGRAPH_CHECK(igraph_dqueue_int_push(&sinks, i)); + IGRAPH_CHECK(igraph_dqueue_int_push(&sinks, u)); } } /* While we have any nodes left... */ while (nodes_left > 0) { + /* (1) Remove the sources one by one */ while (!igraph_dqueue_int_empty(&sources)) { - i = igraph_dqueue_int_pop(&sources); + const igraph_integer_t u = igraph_dqueue_int_pop(&sources); /* Add the node to the ordering */ - ordering[i] = order_next_pos++; + VECTOR(ordering)[u] = order_next_pos++; /* Exclude the node from further searches */ - VECTOR(indegrees)[i] = VECTOR(outdegrees)[i] = -1; + VECTOR(indegrees)[u] = VECTOR(outdegrees)[u] = -1; /* Get the neighbors and decrease their degrees */ - IGRAPH_CHECK(igraph_incident(graph, &neis, i, - IGRAPH_OUT)); - j = igraph_vector_int_size(&neis); - for (i = 0; i < j; i++) { - eid = VECTOR(neis)[i]; - k = IGRAPH_TO(graph, eid); - if (VECTOR(indegrees)[k] <= 0) { + IGRAPH_CHECK(igraph_incident(graph, &neis, u, IGRAPH_OUT)); + neis_size = igraph_vector_int_size(&neis); + for (igraph_integer_t i = 0; i < neis_size; i++) { + const igraph_integer_t eid = VECTOR(neis)[i]; + const igraph_integer_t w = IGRAPH_TO(graph, eid); + if (VECTOR(indegrees)[w] <= 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_int_push(&sources, k)); + VECTOR(indegrees)[w]--; + VECTOR(instrengths)[w] -= (weights ? VECTOR(*weights)[eid] : 1.0); + if (VECTOR(indegrees)[w] == 0) { + IGRAPH_CHECK(igraph_dqueue_int_push(&sources, w)); } } nodes_left--; @@ -277,31 +595,30 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* (2) Remove the sinks one by one */ while (!igraph_dqueue_int_empty(&sinks)) { - i = igraph_dqueue_int_pop(&sinks); + const igraph_integer_t u = igraph_dqueue_int_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) { + if (VECTOR(indegrees)[u] < 0) { continue; } /* Add the node to the ordering */ - ordering[i] = order_next_neg--; + VECTOR(ordering)[u] = order_next_neg--; /* Exclude the node from further searches */ - VECTOR(indegrees)[i] = VECTOR(outdegrees)[i] = -1; + VECTOR(indegrees)[u] = VECTOR(outdegrees)[u] = -1; /* Get the neighbors and decrease their degrees */ - IGRAPH_CHECK(igraph_incident(graph, &neis, i, - IGRAPH_IN)); - j = igraph_vector_int_size(&neis); - for (i = 0; i < j; i++) { - eid = VECTOR(neis)[i]; - k = IGRAPH_FROM(graph, eid); - if (VECTOR(outdegrees)[k] <= 0) { + IGRAPH_CHECK(igraph_incident(graph, &neis, u, IGRAPH_IN)); + neis_size = igraph_vector_int_size(&neis); + for (igraph_integer_t i = 0; i < neis_size; i++) { + const igraph_integer_t eid = VECTOR(neis)[i]; + const igraph_integer_t w = IGRAPH_FROM(graph, eid); + if (VECTOR(outdegrees)[w] <= 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_int_push(&sinks, k)); + VECTOR(outdegrees)[w]--; + VECTOR(outstrengths)[w] -= (weights ? VECTOR(*weights)[eid] : 1.0); + if (VECTOR(outdegrees)[w] == 0) { + IGRAPH_CHECK(igraph_dqueue_int_push(&sinks, w)); } } nodes_left--; @@ -309,52 +626,51 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* (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) { + igraph_integer_t v = -1; + igraph_real_t maxdiff = -IGRAPH_INFINITY; + for (igraph_integer_t u = 0; u < no_of_nodes; u++) { + if (VECTOR(outdegrees)[u] < 0) { continue; } - diff = VECTOR(outstrengths)[i] - VECTOR(instrengths)[i]; + igraph_real_t diff = VECTOR(outstrengths)[u] - VECTOR(instrengths)[u]; if (diff > maxdiff) { maxdiff = diff; - v = i; + v = u; } } if (v >= 0) { /* Remove vertex v */ - ordering[v] = order_next_pos++; + VECTOR(ordering)[v] = order_next_pos++; /* Remove outgoing edges */ - IGRAPH_CHECK(igraph_incident(graph, &neis, v, - IGRAPH_OUT)); - j = igraph_vector_int_size(&neis); - for (i = 0; i < j; i++) { - eid = VECTOR(neis)[i]; - k = IGRAPH_TO(graph, eid); - if (VECTOR(indegrees)[k] <= 0) { + IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_OUT)); + neis_size = igraph_vector_int_size(&neis); + for (igraph_integer_t i = 0; i < neis_size; i++) { + const igraph_integer_t eid = VECTOR(neis)[i]; + const igraph_integer_t w = IGRAPH_TO(graph, eid); + if (VECTOR(indegrees)[w] <= 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_int_push(&sources, k)); + VECTOR(indegrees)[w]--; + VECTOR(instrengths)[w] -= (weights ? VECTOR(*weights)[eid] : 1.0); + if (VECTOR(indegrees)[w] == 0) { + IGRAPH_CHECK(igraph_dqueue_int_push(&sources, w)); } } /* Remove incoming edges */ - IGRAPH_CHECK(igraph_incident(graph, &neis, v, - IGRAPH_IN)); - j = igraph_vector_int_size(&neis); - for (i = 0; i < j; i++) { - eid = VECTOR(neis)[i]; - k = IGRAPH_FROM(graph, eid); - if (VECTOR(outdegrees)[k] <= 0) { + IGRAPH_CHECK(igraph_incident(graph, &neis, v, IGRAPH_IN)); + neis_size = igraph_vector_int_size(&neis); + for (igraph_integer_t i = 0; i < neis_size; i++) { + const igraph_integer_t eid = VECTOR(neis)[i]; + const igraph_integer_t w = IGRAPH_FROM(graph, eid); + if (VECTOR(outdegrees)[w] <= 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_int_push(&sinks, k)); + VECTOR(outdegrees)[w]--; + VECTOR(outstrengths)[w] -= (weights ? VECTOR(*weights)[eid] : 1.0); + if (VECTOR(outdegrees)[w] == 0 && VECTOR(indegrees)[w] > 0) { + IGRAPH_CHECK(igraph_dqueue_int_push(&sinks, w)); } } @@ -364,29 +680,29 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec } } - igraph_dqueue_int_destroy(&sinks); - igraph_dqueue_int_destroy(&sources); - igraph_vector_int_destroy(&neis); igraph_vector_destroy(&outstrengths); igraph_vector_destroy(&instrengths); igraph_vector_int_destroy(&outdegrees); igraph_vector_int_destroy(&indegrees); - IGRAPH_FINALLY_CLEAN(7); + igraph_dqueue_int_destroy(&sinks); + igraph_dqueue_int_destroy(&sources); + IGRAPH_FINALLY_CLEAN(6); /* Tidy up the ordering */ - for (i = 0; i < no_of_nodes; i++) { - if (ordering[i] < 0) { - ordering[i] += no_of_nodes; + for (igraph_integer_t i = 0; i < no_of_nodes; i++) { + if (VECTOR(ordering)[i] < 0) { + VECTOR(ordering)[i] += no_of_nodes; } } /* Find the feedback edges based on the ordering */ if (result) { igraph_vector_int_clear(result); - for (i = 0; i < no_of_edges; i++) { - igraph_integer_t from = IGRAPH_FROM(graph, i), to = IGRAPH_TO(graph, i); - if (from == to || ordering[from] > ordering[to]) { - IGRAPH_CHECK(igraph_vector_int_push_back(result, i)); + for (igraph_integer_t eid = 0; eid < no_of_edges; eid++) { + igraph_integer_t from = IGRAPH_FROM(graph, eid); + igraph_integer_t to = IGRAPH_TO(graph, eid); + if (from == to || VECTOR(ordering)[from] > VECTOR(ordering)[to]) { + IGRAPH_CHECK(igraph_vector_int_push_back(result, eid)); } } } @@ -394,28 +710,24 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec /* If we have also requested a layering, return that as well */ if (layers) { igraph_vector_int_t ranks; - igraph_vector_int_t order_vec; IGRAPH_CHECK(igraph_vector_int_resize(layers, no_of_nodes)); igraph_vector_int_null(layers); - igraph_vector_int_view(&order_vec, ordering, no_of_nodes); - - IGRAPH_VECTOR_INT_INIT_FINALLY(&neis, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&ranks, 0); - IGRAPH_CHECK(igraph_vector_int_qsort_ind(&order_vec, &ranks, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_int_sort_ind(&ordering, &ranks, IGRAPH_ASCENDING)); - for (i = 0; i < no_of_nodes; i++) { + for (igraph_integer_t i = 0; i < no_of_nodes; i++) { igraph_integer_t from = VECTOR(ranks)[i]; IGRAPH_CHECK(igraph_neighbors(graph, &neis, from, IGRAPH_OUT)); - k = igraph_vector_int_size(&neis); - for (j = 0; j < k; j++) { + neis_size = igraph_vector_int_size(&neis); + for (igraph_integer_t j = 0; j < neis_size; j++) { igraph_integer_t to = VECTOR(neis)[j]; if (from == to) { continue; } - if (ordering[from] > ordering[to]) { + if (VECTOR(ordering)[from] > VECTOR(ordering)[to]) { continue; } if (VECTOR(*layers)[to] < VECTOR(*layers)[from] + 1) { @@ -424,30 +736,33 @@ igraph_error_t igraph_i_feedback_arc_set_eades(const igraph_t *graph, igraph_vec } } - igraph_vector_int_destroy(&neis); igraph_vector_int_destroy(&ranks); - IGRAPH_FINALLY_CLEAN(2); + IGRAPH_FINALLY_CLEAN(1); } /* Free the ordering vector */ - IGRAPH_FREE(ordering); - IGRAPH_FINALLY_CLEAN(1); + igraph_vector_int_destroy(&neis); + igraph_vector_int_destroy(&ordering); + IGRAPH_FINALLY_CLEAN(2); return IGRAPH_SUCCESS; } + /** - * Solves the feedback arc set problem using integer programming. + * Solves the feedback arc set problem with integer programming, + * using the triangle inequalities formulation. */ -igraph_error_t igraph_i_feedback_arc_set_ip(const igraph_t *graph, igraph_vector_int_t *result, - const igraph_vector_t *weights) { +igraph_error_t igraph_i_feedback_arc_set_ip_ti( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *weights) { #ifndef HAVE_GLPK IGRAPH_ERROR("GLPK is not available.", IGRAPH_UNIMPLEMENTED); #else + const igraph_integer_t no_of_vertices = igraph_vcount(graph); + const igraph_integer_t no_of_edges = igraph_ecount(graph); 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_int_t membership, *vec; igraph_vector_int_t ordering, vertex_remapping; igraph_vector_int_list_t vertices_by_components, edges_by_components; @@ -463,7 +778,7 @@ igraph_error_t igraph_i_feedback_arc_set_ip(const igraph_t *graph, igraph_vector igraph_vector_int_clear(result); /* Decompose the graph into connected components */ - IGRAPH_CHECK(igraph_connected_components(graph, &membership, 0, &no_of_components, IGRAPH_WEAK)); + IGRAPH_CHECK(igraph_connected_components(graph, &membership, NULL, &no_of_components, IGRAPH_WEAK)); /* Construct vertex and edge lists for each of the components */ IGRAPH_VECTOR_INT_LIST_INIT_FINALLY(&vertices_by_components, no_of_components); @@ -614,7 +929,8 @@ igraph_error_t igraph_i_feedback_arc_set_ip(const igraph_t *graph, igraph_vector } /* Solve the problem */ - IGRAPH_GLPK_CHECK(glp_intopt(ip, &parm), "Feedback arc set using IP failed"); + IGRAPH_GLPK_CHECK(glp_intopt(ip, &parm), + "Feedback arc set using IP with triangle inequalities failed"); /* Find the ordering of the vertices */ IGRAPH_CHECK(igraph_vector_int_resize(&ordering, n)); @@ -662,3 +978,347 @@ igraph_error_t igraph_i_feedback_arc_set_ip(const igraph_t *graph, igraph_vector return IGRAPH_SUCCESS; #endif } + + +/** + * Incremental constraint generation based integer programming implementation + * for feedback arc set (FAS) and feedback vertex set (FVS). + * + * b_i are binary variables indicating the presence of edge/vertex i in the + * FAS/FVS. w_i is the weight of edge/vertex i. + * + * We minimize + * + * sum_i w_i b_i + * + * subject to the constraints + * + * sum_i c^k_i b_i >= 1 + * + * where c^k_i is a binary coefficient indicating if edge/vertex i is present + * in cycle k. + * + * While this must hold for all cycles (all cycles must be broken), + * we generate cycles incrementally, re-solving the problem after + * each step. New cycles are generated in such a way as to avoid + * the feedback set from the previous solution step. + */ + +#define VAR_TO_ID(j) ((j) - 1) + +/* Helper data structure for adding rows to GLPK problems. + * ind[] and val[] use one-based indexing, in line with GLPK's convention. + * Storing the zero-based ind0/val0 and the offset ind/val is necessary + * to avoid GCC warnings. */ +typedef struct { + int alloc_size; + int *ind0, *ind; + double *val0, *val; +} rowdata_t; + +static igraph_error_t rowdata_init(rowdata_t *rd, int size) { + int *ind0 = IGRAPH_CALLOC(size, int); + IGRAPH_CHECK_OOM(ind0, "Insufficient memory for feedback arc set."); + IGRAPH_FINALLY(igraph_free, ind0); + double *val0 = IGRAPH_CALLOC(size, double); + IGRAPH_CHECK_OOM(val0, "Insufficient memory for feedback arc set."); + for (int i=0; i < size; i++) { + val0[i] = 1.0; + } + rd->alloc_size = size; + rd->ind0 = ind0; + rd->ind = ind0 - 1; + rd->val0 = val0; + rd->val = val0 - 1; + IGRAPH_FINALLY_CLEAN(1); + return IGRAPH_SUCCESS; +} + +static igraph_error_t rowdata_set(rowdata_t *rd, const igraph_vector_int_t *idx) { + int size = igraph_vector_int_size(idx); + + /* Expand size if needed */ + if (size > rd->alloc_size) { + int new_alloc_size = 2 * rd->alloc_size; + if (size > new_alloc_size) { + new_alloc_size = size; + } + + int *ind0 = rd->ind0; + double *val0 = rd->val0; + + ind0 = IGRAPH_REALLOC(ind0, new_alloc_size, int); + IGRAPH_CHECK_OOM(ind0, "Insufficient memory for feedback arc set."); + rd->ind0 = ind0; + rd->ind = ind0 - 1; + + val0 = IGRAPH_REALLOC(val0, new_alloc_size, double); + IGRAPH_CHECK_OOM(val0, "Insufficient memory for feedback arc set."); + for (int i = rd->alloc_size; i < new_alloc_size; i++) { + val0[i] = 1.0; + } + rd->val0 = val0; + rd->val = val0 - 1; + + rd->alloc_size = new_alloc_size; + } + + for (int i = 0; i < size; i++) { + rd->ind0[i] = VECTOR(*idx)[i] + 1; + } + + return IGRAPH_SUCCESS; +} + +static void rowdata_destroy(rowdata_t *rd) { + igraph_free(rd->ind0); + igraph_free(rd->val0); +} + +igraph_error_t igraph_i_feedback_arc_set_ip_cg( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *weights) { + +#ifndef HAVE_GLPK + IGRAPH_ERROR("GLPK is not available.", IGRAPH_UNIMPLEMENTED); +#else + const igraph_integer_t ecount = igraph_ecount(graph); + igraph_bool_t is_dag; + igraph_bitset_t removed; + igraph_vector_int_t cycle; + glp_prob *ip; + glp_iocp parm; + rowdata_t rd; + int var_count; + + /* Avoid starting up the IP machinery for DAGs. */ + IGRAPH_CHECK(igraph_is_dag(graph, &is_dag)); + if (is_dag) { + igraph_vector_int_clear(result); + return IGRAPH_SUCCESS; + } + + if (ecount > INT_MAX) { + IGRAPH_ERROR("Feedback arc set problem too large for GLPK.", IGRAPH_EOVERFLOW); + } + + var_count = (int) ecount; + + /* TODO: In-depth investigation of whether decomposing to SCCs helps performance. + * Basic benchmarking on sparse random graphs with mean degrees between 1-2 + * indicate no benefit from avoiding creating GLPK variables for non-cycle edges. */ + + IGRAPH_BITSET_INIT_FINALLY(&removed, ecount); + IGRAPH_VECTOR_INT_INIT_FINALLY(&cycle, 0); + + IGRAPH_CHECK(rowdata_init(&rd, 20)); + IGRAPH_FINALLY(rowdata_destroy, &rd); + + /* Configure GLPK */ + IGRAPH_GLPK_SETUP(); + glp_init_iocp(&parm); + parm.br_tech = GLP_BR_MFV; + parm.bt_tech = GLP_BT_BLB; + parm.pp_tech = GLP_PP_ALL; + parm.presolve = GLP_ON; + parm.cb_func = igraph_i_glpk_interruption_hook; + + ip = glp_create_prob(); + IGRAPH_FINALLY(igraph_i_glp_delete_prob, ip); + + glp_set_obj_dir(ip, GLP_MIN); + + glp_add_cols(ip, var_count); + for (int j = 1; j <= var_count; j++) { + glp_set_obj_coef(ip, j, weights ? VECTOR(*weights)[ VAR_TO_ID(j) ] : 1); + glp_set_col_kind(ip, j, GLP_BV); + } + + while (true) { + int cycle_size, row; + + IGRAPH_CHECK(igraph_i_find_cycle(graph, NULL, &cycle, NULL, IGRAPH_OUT, &removed)); + + cycle_size = (int) igraph_vector_int_size(&cycle); + + if (cycle_size == 0) break; /* no more cycles, we're done */ + + IGRAPH_CHECK(rowdata_set(&rd, &cycle)); + + row = glp_add_rows(ip, 1); + glp_set_row_bnds(ip, row, GLP_LO, 1, 0); + glp_set_mat_row(ip, row, cycle_size, rd.ind, rd.val); + + /* Add as many edge-disjoint cycles at once as possible. */ + while (true) { + for (int i=0; i < cycle_size; i++) { + IGRAPH_BIT_SET(removed, VECTOR(cycle)[i]); + } + IGRAPH_CHECK(igraph_i_find_cycle(graph, NULL, &cycle, NULL, IGRAPH_OUT, &removed)); + + cycle_size = (int) igraph_vector_int_size(&cycle); + if (cycle_size == 0) break; /* no more edge disjoint cycles */ + + IGRAPH_CHECK(rowdata_set(&rd, &cycle)); + + row = glp_add_rows(ip, 1); + glp_set_row_bnds(ip, row, GLP_LO, 1, 0); + glp_set_mat_row(ip, row, cycle_size, rd.ind, rd.val); + } + + IGRAPH_GLPK_CHECK(glp_intopt(ip, &parm), + "Feedback arc set using IP with incremental cycle generation failed"); + + igraph_vector_int_clear(result); + igraph_bitset_null(&removed); + for (int j=1; j <= var_count; j++) { + if (glp_mip_col_val(ip, j) > 0) { + igraph_integer_t i = VAR_TO_ID(j); + IGRAPH_CHECK(igraph_vector_int_push_back(result, i)); + IGRAPH_BIT_SET(removed, i); + } + } + } + + /* Clean up */ + glp_delete_prob(ip); + rowdata_destroy(&rd); + igraph_vector_int_destroy(&cycle); + igraph_bitset_destroy(&removed); + IGRAPH_FINALLY_CLEAN(4); + + return IGRAPH_SUCCESS; +#endif +} + + +igraph_error_t igraph_i_feedback_vertex_set_ip_cg( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *vertex_weights) { +#ifndef HAVE_GLPK + IGRAPH_ERROR("GLPK is not available.", IGRAPH_UNIMPLEMENTED); +#else + + const igraph_integer_t vcount = igraph_vcount(graph); + const igraph_integer_t ecount = igraph_ecount(graph); + igraph_bool_t is_acyclic; + igraph_bitset_t removed; + igraph_vector_int_t cycle; + igraph_vector_int_t incident; + glp_prob *ip; + glp_iocp parm; + rowdata_t rd; + int var_count; + + /* Avoid starting up the IP machinery for acyclic graphs. */ + IGRAPH_CHECK(igraph_is_acyclic(graph, &is_acyclic)); + + if (is_acyclic) { + igraph_vector_int_clear(result); + return IGRAPH_SUCCESS; + } + + if (vcount > INT_MAX) { + IGRAPH_ERROR("Feedback vertex set problem too large for GLPK.", IGRAPH_EOVERFLOW); + } + + var_count = (int) vcount; + + IGRAPH_BITSET_INIT_FINALLY(&removed, ecount); + IGRAPH_VECTOR_INT_INIT_FINALLY(&cycle, 0); + IGRAPH_VECTOR_INT_INIT_FINALLY(&incident, 0); + IGRAPH_CHECK(rowdata_init(&rd, 20)); + IGRAPH_FINALLY(rowdata_destroy, &rd); + + /* Configure GLPK */ + IGRAPH_GLPK_SETUP(); + glp_init_iocp(&parm); + parm.br_tech = GLP_BR_MFV; + parm.bt_tech = GLP_BT_BLB; + parm.pp_tech = GLP_PP_ALL; + parm.presolve = GLP_ON; + parm.cb_func = igraph_i_glpk_interruption_hook; + + ip = glp_create_prob(); + IGRAPH_FINALLY(igraph_i_glp_delete_prob, ip); + + glp_set_obj_dir(ip, GLP_MIN); + + glp_add_cols(ip, var_count); + for (int j = 1; j <= var_count; j++) { + glp_set_obj_coef(ip, j, vertex_weights ? VECTOR(*vertex_weights)[ VAR_TO_ID(j) ] : 1); + glp_set_col_kind(ip, j, GLP_BV); + } + + while (true) { + int cycle_size, row; + + IGRAPH_CHECK(igraph_i_find_cycle(graph, &cycle, NULL, NULL, IGRAPH_OUT, &removed)); + + cycle_size = (int) igraph_vector_int_size(&cycle); + + if (cycle_size == 0) break; /* no more cycles, we're done */ + + IGRAPH_CHECK(rowdata_set(&rd, &cycle)); + + row = glp_add_rows(ip, 1); + glp_set_row_bnds(ip, row, GLP_LO, 1, 0); + glp_set_mat_row(ip, row, cycle_size, rd.ind, rd.val); + + /* Add as many vertex-disjoint cycles at once as possible. */ + while (true) { + for (int i=0; i < cycle_size; i++) { + IGRAPH_CHECK(igraph_incident(graph, &incident, VECTOR(cycle)[i], IGRAPH_ALL)); + const igraph_integer_t incident_size = igraph_vector_int_size(&incident); + for (igraph_integer_t j = 0; j < incident_size; j++) { + igraph_integer_t eid = VECTOR(incident)[j]; + IGRAPH_BIT_SET(removed, eid); + } + } + IGRAPH_CHECK(igraph_i_find_cycle(graph, &cycle, NULL, NULL, IGRAPH_OUT, &removed)); + + cycle_size = (int) igraph_vector_int_size(&cycle); + if (cycle_size == 0) break; /* no more vertex disjoint cycles */ + + IGRAPH_CHECK(rowdata_set(&rd, &cycle)); + + row = glp_add_rows(ip, 1); + glp_set_row_bnds(ip, row, GLP_LO, 1, 0); + glp_set_mat_row(ip, row, cycle_size, rd.ind, rd.val); + } + + IGRAPH_GLPK_CHECK(glp_intopt(ip, &parm), + "Feedback vertex set using IP with incremental cycle generation failed"); + + igraph_vector_int_clear(result); + igraph_bitset_null(&removed); + + for (int j=1; j <= var_count; j++) { + if (glp_mip_col_val(ip, j) > 0) { + igraph_integer_t i = VAR_TO_ID(j); + IGRAPH_CHECK(igraph_vector_int_push_back(result, i)); + + IGRAPH_CHECK(igraph_incident(graph, &incident, i, IGRAPH_ALL)); + + const igraph_integer_t incident_size = igraph_vector_int_size(&incident); + for (igraph_integer_t k = 0; k < incident_size; k++) { + igraph_integer_t eid = VECTOR(incident)[k]; + IGRAPH_BIT_SET(removed, eid); + } + } + } + } + + /* Clean up */ + glp_delete_prob(ip); + rowdata_destroy(&rd); + igraph_vector_int_destroy(&cycle); + igraph_vector_int_destroy(&incident); + igraph_bitset_destroy(&removed); + IGRAPH_FINALLY_CLEAN(5); + + return IGRAPH_SUCCESS; +#endif +} + +#undef VAR_TO_ID diff --git a/src/vendor/cigraph/src/misc/feedback_arc_set.h b/src/vendor/cigraph/src/misc/feedback_arc_set.h index 7d34eb0b60..447405cb81 100644 --- a/src/vendor/cigraph/src/misc/feedback_arc_set.h +++ b/src/vendor/cigraph/src/misc/feedback_arc_set.h @@ -1,7 +1,6 @@ -/* -*- mode: C -*- */ /* IGraph library. - Copyright (C) 2009-2021 The igraph development team + Copyright (C) 2009-2024 The igraph development 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 @@ -14,10 +13,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - 02110-1301 USA - + along with this program. If not, see . */ #ifndef IGRAPH_FEEDBACK_ARC_SET_INTERNAL_H @@ -33,7 +29,13 @@ igraph_error_t igraph_i_feedback_arc_set_eades( const igraph_t *graph, igraph_vector_int_t *result, const igraph_vector_t *weights, igraph_vector_int_t *layering ); -igraph_error_t igraph_i_feedback_arc_set_ip( +igraph_error_t igraph_i_feedback_arc_set_ip_ti( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *weights); +igraph_error_t igraph_i_feedback_arc_set_ip_cg( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *weights); +igraph_error_t igraph_i_feedback_arc_set_ip_cb( const igraph_t *graph, igraph_vector_int_t *result, const igraph_vector_t *weights); igraph_error_t igraph_i_feedback_arc_set_undirected( @@ -41,6 +43,10 @@ igraph_error_t igraph_i_feedback_arc_set_undirected( const igraph_vector_t *weights, igraph_vector_int_t *layering ); +igraph_error_t igraph_i_feedback_vertex_set_ip_cg( + const igraph_t *graph, igraph_vector_int_t *result, + const igraph_vector_t *weights); + __END_DECLS #endif diff --git a/src/vendor/cigraph/src/misc/motifs.c b/src/vendor/cigraph/src/misc/motifs.c index e1df14ffb2..e86e7981f7 100644 --- a/src/vendor/cigraph/src/misc/motifs.c +++ b/src/vendor/cigraph/src/misc/motifs.c @@ -95,8 +95,9 @@ static igraph_error_t igraph_i_motifs_randesu_update_hist( * 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 \p size) to find all motifs - * in a graph. + * To perform a complete search and find all motifs, supply + * either an all-zero vector of length \p size, or (since + * igraph 0.10.14) a \c NULL pointer. * \return Error code. * * \sa \ref igraph_motifs_randesu_estimate() for estimating the number @@ -150,7 +151,7 @@ igraph_error_t igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *his } } - if (igraph_vector_size(cut_prob) != size) { + if (cut_prob != NULL && igraph_vector_size(cut_prob) != size) { IGRAPH_ERRORF("Cut probability vector size (%" IGRAPH_PRId ") must agree with motif size (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_size(cut_prob), size); } @@ -223,8 +224,9 @@ igraph_error_t igraph_motifs_randesu(const igraph_t *graph, igraph_vector_t *his * 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. + * To perform a complete search and find all motifs, supply + * either an all-zero vector of length \p size, or (since + * igraph 0.10.14) a \c NULL pointer. * \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. @@ -303,7 +305,7 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte } } - if (igraph_vector_size(cut_prob) != size) { + if (cut_prob != NULL && igraph_vector_size(cut_prob) != size) { IGRAPH_ERRORF("Cut probability vector size (%" IGRAPH_PRId ") must agree with motif size (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_size(cut_prob), size); } @@ -333,8 +335,10 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte IGRAPH_ALLOW_INTERRUPTION(); - if (VECTOR(*cut_prob)[0] == 1 || RNG_UNIF01() < VECTOR(*cut_prob)[0]) { - continue; + if (cut_prob) { + if (VECTOR(*cut_prob)[0] == 1 || RNG_UNIF01() < VECTOR(*cut_prob)[0]) { + continue; + } } /* init G */ @@ -359,7 +363,7 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte igraph_stack_int_clear(&stack); while (level > 1 || !igraph_vector_int_empty(&adjverts)) { - igraph_real_t cp = VECTOR(*cut_prob)[level]; + igraph_real_t cp = cut_prob ? VECTOR(*cut_prob)[level] : 0; if (level == size - 1) { s = igraph_vector_int_size(&adjverts) / 2; @@ -520,10 +524,11 @@ igraph_error_t igraph_motifs_randesu_callback(const igraph_t *graph, igraph_inte * \param graph The graph object to study. * \param est Pointer to an integer, the result will be stored here. * \param size The size of the subgraphs 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 \p size - * zeros here to count all the motifs in the sample. + * \param cut_prob Vector of probabilities for cutting the search tree + * at a given level. The first element is the first level, etc. + * To perform a complete search and find all motifs, supply + * either an all-zero vector of length \p size, or (since + * igraph 0.10.14) a \c NULL pointer. * \param sample_size The number of vertices to use as the * sample. This parameter is only used if the \p parsample * argument is a null pointer. @@ -560,7 +565,7 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte IGRAPH_EINVAL, size); } - if (igraph_vector_size(cut_prob) != size) { + if (cut_prob != NULL && igraph_vector_size(cut_prob) != size) { IGRAPH_ERRORF("Cut probability vector size (%" IGRAPH_PRId ") must agree with motif size (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_size(cut_prob), size); } @@ -605,9 +610,10 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte IGRAPH_ALLOW_INTERRUPTION(); - if (VECTOR(*cut_prob)[0] == 1 || - RNG_UNIF01() < VECTOR(*cut_prob)[0]) { - continue; + if (cut_prob) { + if (VECTOR(*cut_prob)[0] == 1 || RNG_UNIF01() < VECTOR(*cut_prob)[0]) { + continue; + } } /* init G */ @@ -632,7 +638,7 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte igraph_stack_int_clear(&stack); while (level > 1 || !igraph_vector_int_empty(&adjverts)) { - igraph_real_t cp = VECTOR(*cut_prob)[level]; + igraph_real_t cp = cut_prob ? VECTOR(*cut_prob)[level] : 0.0; if (level == size - 1) { s = igraph_vector_int_size(&adjverts) / 2; @@ -739,8 +745,11 @@ igraph_error_t igraph_motifs_randesu_estimate(const igraph_t *graph, igraph_inte * \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. + * \param cut_prob Vector of probabilities for cutting the search tree + * at a given level. The first element is the first level, etc. + * To perform a complete search and find all connected subgraphs, + * supply either an all-zero vector of length \p size, or (since + * igraph 0.10.14) a \c NULL pointer. * \return Error code. * \sa \ref igraph_motifs_randesu(), \ref * igraph_motifs_randesu_estimate(). @@ -765,7 +774,7 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t IGRAPH_EINVAL, size); } - if (igraph_vector_size(cut_prob) != size) { + if (cut_prob != NULL && igraph_vector_size(cut_prob) != size) { IGRAPH_ERRORF("Cut probability vector size (%" IGRAPH_PRId ") must agree with motif size (%" IGRAPH_PRId ").", IGRAPH_EINVAL, igraph_vector_size(cut_prob), size); } @@ -788,9 +797,10 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t IGRAPH_ALLOW_INTERRUPTION(); - if (VECTOR(*cut_prob)[0] == 1 || - RNG_UNIF01() < VECTOR(*cut_prob)[0]) { - continue; + if (cut_prob) { + if (VECTOR(*cut_prob)[0] == 1 || RNG_UNIF01() < VECTOR(*cut_prob)[0]) { + continue; + } } /* init G */ @@ -815,7 +825,7 @@ igraph_error_t igraph_motifs_randesu_no(const igraph_t *graph, igraph_integer_t igraph_stack_int_clear(&stack); while (level > 1 || !igraph_vector_int_empty(&adjverts)) { - igraph_real_t cp = VECTOR(*cut_prob)[level]; + igraph_real_t cp = cut_prob ? VECTOR(*cut_prob)[level] : 0.0; if (level == size - 1) { s = igraph_vector_int_size(&adjverts) / 2; diff --git a/src/vendor/cigraph/src/misc/other.c b/src/vendor/cigraph/src/misc/other.c index 8d22697687..095677ac76 100644 --- a/src/vendor/cigraph/src/misc/other.c +++ b/src/vendor/cigraph/src/misc/other.c @@ -168,7 +168,7 @@ igraph_error_t igraph_convex_hull( /* Sort points by angles */ IGRAPH_VECTOR_INT_INIT_FINALLY(&order, no_of_nodes); - IGRAPH_CHECK(igraph_vector_qsort_ind(&angles, &order, IGRAPH_ASCENDING)); + IGRAPH_CHECK(igraph_vector_sort_ind(&angles, &order, IGRAPH_ASCENDING)); /* Check if two points have the same angle. If so, keep only the point that * is farthest from the pivot */ diff --git a/src/vendor/cigraph/src/misc/spanning_trees.c b/src/vendor/cigraph/src/misc/spanning_trees.c index bd83092246..77413945a1 100644 --- a/src/vendor/cigraph/src/misc/spanning_trees.c +++ b/src/vendor/cigraph/src/misc/spanning_trees.c @@ -88,6 +88,8 @@ igraph_error_t igraph_minimum_spanning_tree( * \function igraph_minimum_spanning_tree_unweighted * \brief Calculates one minimum spanning tree of an unweighted graph. * + * \deprecated-by igraph_minimum_spanning_tree 0.10.14 + * * 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. @@ -139,6 +141,8 @@ igraph_error_t igraph_minimum_spanning_tree_unweighted(const igraph_t *graph, * \function igraph_minimum_spanning_tree_prim * \brief Calculates one minimum spanning tree of a weighted graph. * + * \deprecated-by igraph_minimum_spanning_tree 0.10.14 + * * Finds a spanning tree or spanning forest for which the sum of edge * weights is the smallest. This function uses Prim's method for carrying * out the computation. diff --git a/src/vendor/cigraph/src/operators/compose.c b/src/vendor/cigraph/src/operators/compose.c index 6c69f4ba82..fdcbc7b061 100644 --- a/src/vendor/cigraph/src/operators/compose.c +++ b/src/vendor/cigraph/src/operators/compose.c @@ -36,17 +36,17 @@ * and only if there is a k vertex, such that the first graph * contains an (i,k) edge and the second graph a (k,j) edge. * - * This is of course exactly the composition of two - * binary relations. + * + * This is of course exactly the composition of two binary relations. * - * The two graphs must have the same directedness, - * otherwise the function returns with an error. - * Note that for undirected graphs the two relations are by definition - * symmetric. + * + * The two graphs must have the same directedness, otherwise the function + * returns with an error. 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 g1 The first 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 @@ -64,25 +64,25 @@ * * \example examples/simple/igraph_compose.c */ -igraph_error_t igraph_compose(igraph_t *res, const igraph_t *g1, const igraph_t *g2, - igraph_vector_int_t *edge_map1, igraph_vector_int_t *edge_map2) { - - igraph_integer_t no_of_nodes_left = igraph_vcount(g1); - igraph_integer_t no_of_nodes_right = igraph_vcount(g2); - igraph_integer_t no_of_nodes; - igraph_bool_t directed = igraph_is_directed(g1); +igraph_error_t igraph_compose(igraph_t *res, + const igraph_t *g1, + const igraph_t *g2, + igraph_vector_int_t *edge_map1, + igraph_vector_int_t *edge_map2) { + + const igraph_integer_t no_of_nodes_left = igraph_vcount(g1); + const igraph_integer_t no_of_nodes_right = igraph_vcount(g2); + const igraph_bool_t directed = igraph_is_directed(g1); + const igraph_integer_t no_of_nodes = no_of_nodes_left > no_of_nodes_right ? + no_of_nodes_left : no_of_nodes_right; igraph_vector_int_t edges; igraph_vector_int_t neis1, neis2; - igraph_integer_t 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_INT_INIT_FINALLY(&edges, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis1, 0); IGRAPH_VECTOR_INT_INIT_FINALLY(&neis2, 0); @@ -94,22 +94,20 @@ igraph_error_t igraph_compose(igraph_t *res, const igraph_t *g1, const igraph_t igraph_vector_int_clear(edge_map2); } - for (i = 0; i < no_of_nodes_left; i++) { + for (igraph_integer_t i = 0; i < no_of_nodes_left; i++) { IGRAPH_ALLOW_INTERRUPTION(); - IGRAPH_CHECK(igraph_incident(g1, &neis1, i, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(g1, &neis1, i, IGRAPH_OUT)); while (!igraph_vector_int_empty(&neis1)) { - igraph_integer_t con = igraph_vector_int_pop_back(&neis1); - igraph_integer_t v1 = IGRAPH_OTHER(g1, con, i); + const igraph_integer_t con = igraph_vector_int_pop_back(&neis1); + const igraph_integer_t v1 = IGRAPH_OTHER(g1, con, i); if (v1 < no_of_nodes_right) { - IGRAPH_CHECK(igraph_incident(g2, &neis2, v1, - IGRAPH_OUT)); + IGRAPH_CHECK(igraph_incident(g2, &neis2, v1, IGRAPH_OUT)); } else { continue; } while (!igraph_vector_int_empty(&neis2)) { - igraph_integer_t con2 = igraph_vector_int_pop_back(&neis2); - igraph_integer_t v2 = IGRAPH_OTHER(g2, con2, v1); + const igraph_integer_t con2 = igraph_vector_int_pop_back(&neis2); + const igraph_integer_t v2 = IGRAPH_OTHER(g2, con2, v1); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, i)); IGRAPH_CHECK(igraph_vector_int_push_back(&edges, v2)); if (edge_map1) { diff --git a/src/vendor/cigraph/src/operators/rewire.c b/src/vendor/cigraph/src/operators/rewire.c index 299c1bc46c..fd4fbc2447 100644 --- a/src/vendor/cigraph/src/operators/rewire.c +++ b/src/vendor/cigraph/src/operators/rewire.c @@ -189,7 +189,7 @@ igraph_error_t igraph_i_rewire(igraph_t *graph, igraph_integer_t n, igraph_rewir break; default: RNG_END(); - IGRAPH_ERROR("unknown rewiring mode", IGRAPH_EINVMODE); + IGRAPH_ERROR("Invalid rewiring mode.", IGRAPH_EINVAL); } num_swaps++; } diff --git a/src/vendor/cigraph/src/paths/dijkstra.c b/src/vendor/cigraph/src/paths/dijkstra.c index 3f5fa24f9e..784fe33b4c 100644 --- a/src/vendor/cigraph/src/paths/dijkstra.c +++ b/src/vendor/cigraph/src/paths/dijkstra.c @@ -386,11 +386,11 @@ igraph_error_t igraph_shortest_paths_dijkstra(const igraph_t *graph, * Time complexity: O(|E|log|V|+|V|), where |V| is the number of * vertices and |E| is the number of edges * - * \sa \ref igraph_distances_dijkstra() if you only need the path length but + * \sa \ref igraph_distances_dijkstra() if you only need the path lengths but * not the paths themselves; \ref igraph_get_shortest_paths() if all edge * weights are equal; \ref igraph_get_all_shortest_paths() to find all * shortest paths between (source, target) pairs; - * \ref igraph_get_shortest_paths_bellman_ford() if some edge weighted are + * \ref igraph_get_shortest_paths_bellman_ford() if some edge weights are * negative. * * \example examples/simple/igraph_get_shortest_paths_dijkstra.c @@ -768,7 +768,7 @@ igraph_error_t igraph_get_shortest_path_dijkstra(const igraph_t *graph, * vertices and |E| is the number of edges * * \sa \ref igraph_distances_dijkstra() if you only need the path - * length but not the paths themselves, \ref igraph_get_all_shortest_paths() + * lengths 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 diff --git a/src/vendor/cigraph/src/paths/floyd_warshall.c b/src/vendor/cigraph/src/paths/floyd_warshall.c index 19abae6404..18502e4308 100644 --- a/src/vendor/cigraph/src/paths/floyd_warshall.c +++ b/src/vendor/cigraph/src/paths/floyd_warshall.c @@ -248,7 +248,7 @@ static igraph_error_t distances_floyd_warshall_tree(igraph_matrix_t *res) { * \param method The type of the algorithm used. * \clist * \cli IGRAPH_FLOYD_WARSHALL_AUTOMATIC - * tried to select the best performing variant for the current graph; + * tries to select the best performing variant for the current graph; * presently this option always uses the "Tree" method. * \cli IGRAPH_FLOYD_WARSHALL_ORIGINAL * the basic Floyd-Warshall algorithm. diff --git a/src/vendor/cigraph/src/properties/degrees.c b/src/vendor/cigraph/src/properties/degrees.c index 5131fd8be3..fffd2aa334 100644 --- a/src/vendor/cigraph/src/properties/degrees.c +++ b/src/vendor/cigraph/src/properties/degrees.c @@ -731,7 +731,7 @@ igraph_error_t igraph_sort_vertex_ids_by_degree(const igraph_t *graph, igraph_vector_int_t vs_vec; IGRAPH_VECTOR_INT_INIT_FINALLY(°rees, 0); IGRAPH_CHECK(igraph_degree(graph, °rees, vids, mode, loops)); - IGRAPH_CHECK(igraph_vector_int_qsort_ind(°rees, outvids, order)); + IGRAPH_CHECK(igraph_vector_int_sort_ind(°rees, outvids, order)); if (only_indices || igraph_vs_is_all(&vids) ) { igraph_vector_int_destroy(°rees); IGRAPH_FINALLY_CLEAN(1); diff --git a/src/vendor/cigraph/src/properties/loops.c b/src/vendor/cigraph/src/properties/loops.c index 18b5ac1841..02eb59033f 100644 --- a/src/vendor/cigraph/src/properties/loops.c +++ b/src/vendor/cigraph/src/properties/loops.c @@ -69,7 +69,7 @@ igraph_error_t igraph_has_loop(const igraph_t *graph, igraph_bool_t *res) { * \function igraph_is_loop * \brief Find the loop edges in a graph. * - * A loop edge is an edge from a vertex to itself. + * A loop edge, also called a self-loop, 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, @@ -84,7 +84,7 @@ igraph_error_t igraph_has_loop(const igraph_t *graph, igraph_bool_t *res) { * \example examples/simple/igraph_is_loop.c */ igraph_error_t igraph_is_loop(const igraph_t *graph, igraph_vector_bool_t *res, - igraph_es_t es) { + igraph_es_t es) { igraph_eit_t eit; igraph_bool_t found_loop = false; diff --git a/src/vendor/cigraph/src/properties/multiplicity.c b/src/vendor/cigraph/src/properties/multiplicity.c index 9647356ca4..d41678597e 100644 --- a/src/vendor/cigraph/src/properties/multiplicity.c +++ b/src/vendor/cigraph/src/properties/multiplicity.c @@ -217,7 +217,8 @@ igraph_error_t igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res) { * to check all edges. * \return Error code. * - * \sa \ref igraph_count_multiple(), \ref igraph_has_multiple() and \ref igraph_simplify(). + * \sa \ref igraph_count_multiple(), \ref igraph_count_multiple_1(), + * \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 @@ -226,7 +227,7 @@ igraph_error_t igraph_has_multiple(const igraph_t *graph, igraph_bool_t *res) { * \example examples/simple/igraph_is_multiple.c */ igraph_error_t igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *res, - igraph_es_t es) { + igraph_es_t es) { igraph_eit_t eit; igraph_integer_t i, j, n; igraph_lazy_inclist_t inclist; @@ -289,7 +290,8 @@ igraph_error_t igraph_is_multiple(const igraph_t *graph, igraph_vector_bool_t *r * average degree (out-degree in directed graphs) of the vertices at the * tail of the edges. */ -igraph_error_t igraph_count_multiple(const igraph_t *graph, igraph_vector_int_t *res, igraph_es_t es) { +igraph_error_t igraph_count_multiple(const igraph_t *graph, igraph_vector_int_t *res, + igraph_es_t es) { igraph_eit_t eit; igraph_integer_t i, j, n; igraph_lazy_adjlist_t adjlist; @@ -342,7 +344,8 @@ igraph_error_t igraph_count_multiple(const igraph_t *graph, igraph_vector_int_t * * Time complexity: O(d), where d is the out-degree of the tail of the edge. */ -igraph_error_t igraph_count_multiple_1(const igraph_t *graph, igraph_integer_t *res, igraph_integer_t eid) +igraph_error_t igraph_count_multiple_1(const igraph_t *graph, igraph_integer_t *res, + igraph_integer_t eid) { igraph_integer_t i, n, count; igraph_integer_t from = IGRAPH_FROM(graph, eid); @@ -398,7 +401,8 @@ igraph_error_t igraph_count_multiple_1(const igraph_t *graph, igraph_integer_t * * supplied edges. An upper limit of the time complexity is O(n log(|E|)), * |E| is the number of edges in the graph. */ -igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res, igraph_es_t es, igraph_bool_t loops) { +igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res, + igraph_es_t es, igraph_bool_t loops) { igraph_eit_t eit; igraph_lazy_adjlist_t adjlist; @@ -435,7 +439,7 @@ igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res out-list of to */ igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, to); IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); - VECTOR(*res)[i] = igraph_vector_int_binsearch2(neis, from); + VECTOR(*res)[i] = igraph_vector_int_contains_sorted(neis, from); } igraph_lazy_adjlist_destroy(&adjlist); @@ -471,7 +475,8 @@ igraph_error_t igraph_is_mutual(const igraph_t *graph, igraph_vector_bool_t *res * * Time complexity: O(|E| log(d)) where d is the maximum in-degree. */ -igraph_error_t igraph_has_mutual(const igraph_t *graph, igraph_bool_t *res, igraph_bool_t loops) { +igraph_error_t igraph_has_mutual(const igraph_t *graph, igraph_bool_t *res, + igraph_bool_t loops) { igraph_integer_t no_of_edges = igraph_ecount(graph); igraph_lazy_adjlist_t adjlist; @@ -518,7 +523,7 @@ igraph_error_t igraph_has_mutual(const igraph_t *graph, igraph_bool_t *res, igra out-list of to */ igraph_vector_int_t *neis = igraph_lazy_adjlist_get(&adjlist, to); IGRAPH_CHECK_OOM(neis, "Failed to query neighbors."); - if (igraph_vector_int_binsearch2(neis, from)) { + if (igraph_vector_int_contains_sorted(neis, from)) { *res = true; break; } diff --git a/src/vendor/cigraph/src/properties/trees.c b/src/vendor/cigraph/src/properties/trees.c index b076c9a1d9..8a7e8b7eef 100644 --- a/src/vendor/cigraph/src/properties/trees.c +++ b/src/vendor/cigraph/src/properties/trees.c @@ -731,6 +731,9 @@ static igraph_error_t igraph_i_is_forest( is stored here. * \return Error code. * + * \sa \ref igraph_find_cycle() to find a cycle that demonstrates + * that the graph is not acyclic. + * * Time complexity: O(|V|+|E|), where |V| and |E| are the number of * vertices and edges in the original input graph. */ diff --git a/src/vendor/igraph_version.h b/src/vendor/igraph_version.h index 40bf73ba4e..383789a7f4 100644 --- a/src/vendor/igraph_version.h +++ b/src/vendor/igraph_version.h @@ -28,11 +28,11 @@ __BEGIN_DECLS -#define IGRAPH_VERSION "0.10.13-10-g766238c85" +#define IGRAPH_VERSION "0.10.13-109-g03760a09c" #define IGRAPH_VERSION_MAJOR 0 #define IGRAPH_VERSION_MINOR 10 #define IGRAPH_VERSION_PATCH 13 -#define IGRAPH_VERSION_PRERELEASE "10-g766238c85" +#define IGRAPH_VERSION_PRERELEASE "109-g03760a09c" IGRAPH_EXPORT void igraph_version(const char **version_string, int *major, diff --git a/src/vendor/io/pajek-parser.c b/src/vendor/io/pajek-parser.c index 96dc130c5a..e62631deb5 100644 --- a/src/vendor/io/pajek-parser.c +++ b/src/vendor/io/pajek-parser.c @@ -678,18 +678,18 @@ static const yytype_int8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_int16 yyrline[] = { - 0, 188, 188, 199, 199, 201, 201, 203, 205, 215, - 233, 233, 235, 236, 236, 239, 258, 263, 264, 268, - 274, 274, 278, 278, 281, 282, 285, 288, 291, 294, - 297, 300, 303, 306, 309, 314, 317, 320, 323, 326, - 329, 344, 344, 344, 344, 344, 344, 346, 347, 349, - 349, 351, 351, 356, 357, 359, 359, 361, 361, 366, - 366, 370, 370, 373, 374, 377, 380, 383, 386, 389, - 392, 395, 398, 401, 404, 407, 410, 413, 418, 421, - 424, 427, 430, 433, 436, 451, 453, 453, 455, 457, - 457, 459, 461, 466, 468, 468, 470, 472, 472, 474, - 476, 483, 485, 490, 490, 492, 494, 494, 496, 516, - 524, 532, 536, 538, 540, 542 + 0, 188, 188, 199, 199, 201, 201, 203, 205, 216, + 235, 235, 237, 238, 238, 248, 267, 272, 273, 277, + 283, 283, 287, 287, 290, 291, 294, 297, 300, 303, + 306, 309, 312, 315, 318, 323, 326, 329, 332, 335, + 338, 353, 353, 353, 353, 353, 353, 355, 356, 358, + 358, 360, 360, 365, 366, 368, 368, 370, 370, 375, + 375, 379, 379, 382, 383, 386, 389, 392, 395, 398, + 401, 404, 407, 410, 413, 416, 419, 422, 427, 430, + 433, 436, 439, 442, 445, 460, 462, 462, 464, 466, + 466, 468, 470, 475, 477, 477, 479, 481, 481, 483, + 485, 492, 494, 499, 499, 501, 503, 503, 505, 525, + 533, 541, 545, 547, 549, 551 }; #endif @@ -1817,12 +1817,13 @@ YYLTYPE yylloc = yyloc_default; if (context->vcount > IGRAPH_PAJEK_MAX_VERTEX_COUNT) { IGRAPH_YY_ERRORF("Vertex count too large in Pajek file (%" IGRAPH_PRId ").", IGRAPH_EINVAL, context->vcount); } + IGRAPH_YY_CHECK(igraph_bitset_resize(context->seen, context->vcount)); } -#line 1822 "src/vendor/io/pajek-parser.c" +#line 1823 "src/vendor/io/pajek-parser.c" break; case 9: /* verticeshead: "*Vertices line" integer integer */ -#line 215 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 216 "src/vendor/cigraph/src/io/pajek-parser.y" { context->vcount=(yyvsp[-1].intnum); context->vcount2=(yyvsp[0].intnum); @@ -1839,24 +1840,32 @@ YYLTYPE yylloc = yyloc_default; IGRAPH_YY_ERRORF("2-mode vertex count too large in Pajek file (%" IGRAPH_PRId ").", IGRAPH_EINVAL, context->vcount2); } IGRAPH_YY_CHECK(add_bipartite_type(context)); + IGRAPH_YY_CHECK(igraph_bitset_resize(context->seen, context->vcount)); } -#line 1844 "src/vendor/io/pajek-parser.c" +#line 1846 "src/vendor/io/pajek-parser.c" break; case 13: /* $@1: %empty */ -#line 236 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 238 "src/vendor/cigraph/src/io/pajek-parser.y" { context->actvertex=(yyvsp[0].intnum); } -#line 1850 "src/vendor/io/pajek-parser.c" +#line 1852 "src/vendor/io/pajek-parser.c" break; case 14: /* vertexline: vertex $@1 vertexid vertexcoords shape vertparams "end of line" */ -#line 236 "src/vendor/cigraph/src/io/pajek-parser.y" - { } -#line 1856 "src/vendor/io/pajek-parser.c" +#line 238 "src/vendor/cigraph/src/io/pajek-parser.y" + { + igraph_integer_t v = (yyvsp[-6].intnum)-1; /* zero-based vertex ID */ + if (IGRAPH_BIT_TEST(*context->seen, v)) { + IGRAPH_WARNINGF("Vertex ID %" IGRAPH_PRId " appears twice in Pajek file. Duplicate attributes will be overwritten.", v+1); + } else { + IGRAPH_BIT_SET(*context->seen, v); + } + } +#line 1865 "src/vendor/io/pajek-parser.c" break; case 15: /* vertex: integer */ -#line 239 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 248 "src/vendor/cigraph/src/io/pajek-parser.y" { igraph_integer_t v = (yyvsp[0].intnum); /* Per feedback from Pajek's authors, negative signs should be ignored for vertex IDs. @@ -1875,167 +1884,167 @@ YYLTYPE yylloc = yyloc_default; } (yyval.intnum) = v; } -#line 1879 "src/vendor/io/pajek-parser.c" +#line 1888 "src/vendor/io/pajek-parser.c" break; case 16: /* vertexid: word */ -#line 258 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 267 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_vertex_attribute("id", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); IGRAPH_YY_CHECK(add_string_vertex_attribute("name", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 1888 "src/vendor/io/pajek-parser.c" +#line 1897 "src/vendor/io/pajek-parser.c" break; case 18: /* vertexcoords: number number */ -#line 264 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 273 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("x", (yyvsp[-1].realnum), context)); IGRAPH_YY_CHECK(add_numeric_vertex_attribute("y", (yyvsp[0].realnum), context)); } -#line 1897 "src/vendor/io/pajek-parser.c" +#line 1906 "src/vendor/io/pajek-parser.c" break; case 19: /* vertexcoords: number number number */ -#line 268 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 277 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("x", (yyvsp[-2].realnum), context)); IGRAPH_YY_CHECK(add_numeric_vertex_attribute("y", (yyvsp[-1].realnum), context)); IGRAPH_YY_CHECK(add_numeric_vertex_attribute("z", (yyvsp[0].realnum), context)); } -#line 1907 "src/vendor/io/pajek-parser.c" +#line 1916 "src/vendor/io/pajek-parser.c" break; case 21: /* shape: word */ -#line 274 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 283 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_vertex_attribute("shape", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 1915 "src/vendor/io/pajek-parser.c" +#line 1924 "src/vendor/io/pajek-parser.c" break; case 25: /* vertparam: VP_X_FACT number */ -#line 282 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 291 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("xfact", (yyvsp[0].realnum), context)); } -#line 1923 "src/vendor/io/pajek-parser.c" +#line 1932 "src/vendor/io/pajek-parser.c" break; case 26: /* vertparam: VP_Y_FACT number */ -#line 285 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 294 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("yfact", (yyvsp[0].realnum), context)); } -#line 1931 "src/vendor/io/pajek-parser.c" +#line 1940 "src/vendor/io/pajek-parser.c" break; case 27: /* vertparam: VP_LR number */ -#line 288 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 297 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("labeldist", (yyvsp[0].realnum), context)); } -#line 1939 "src/vendor/io/pajek-parser.c" +#line 1948 "src/vendor/io/pajek-parser.c" break; case 28: /* vertparam: VP_LPHI number */ -#line 291 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 300 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("labeldegree2", (yyvsp[0].realnum), context)); } -#line 1947 "src/vendor/io/pajek-parser.c" +#line 1956 "src/vendor/io/pajek-parser.c" break; case 29: /* vertparam: VP_BW number */ -#line 294 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 303 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("framewidth", (yyvsp[0].realnum), context)); } -#line 1955 "src/vendor/io/pajek-parser.c" +#line 1964 "src/vendor/io/pajek-parser.c" break; case 30: /* vertparam: VP_FOS number */ -#line 297 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 306 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("fontsize", (yyvsp[0].realnum), context)); } -#line 1963 "src/vendor/io/pajek-parser.c" +#line 1972 "src/vendor/io/pajek-parser.c" break; case 31: /* vertparam: VP_PHI number */ -#line 300 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 309 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("rotation", (yyvsp[0].realnum), context)); } -#line 1971 "src/vendor/io/pajek-parser.c" +#line 1980 "src/vendor/io/pajek-parser.c" break; case 32: /* vertparam: VP_R number */ -#line 303 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 312 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("radius", (yyvsp[0].realnum), context)); } -#line 1979 "src/vendor/io/pajek-parser.c" +#line 1988 "src/vendor/io/pajek-parser.c" break; case 33: /* vertparam: VP_Q number */ -#line 306 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 315 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("diamondratio", (yyvsp[0].realnum), context)); } -#line 1987 "src/vendor/io/pajek-parser.c" +#line 1996 "src/vendor/io/pajek-parser.c" break; case 34: /* vertparam: VP_LA number */ -#line 309 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 318 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_vertex_attribute("labeldegree", (yyvsp[0].realnum), context)); } -#line 1995 "src/vendor/io/pajek-parser.c" +#line 2004 "src/vendor/io/pajek-parser.c" break; case 35: /* vpword: VP_FONT parstrval */ -#line 314 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 323 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_vertex_attribute("font", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2003 "src/vendor/io/pajek-parser.c" +#line 2012 "src/vendor/io/pajek-parser.c" break; case 36: /* vpword: VP_URL parstrval */ -#line 317 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 326 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_vertex_attribute("url", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2011 "src/vendor/io/pajek-parser.c" +#line 2020 "src/vendor/io/pajek-parser.c" break; case 37: /* vpword: VP_IC parstrval */ -#line 320 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 329 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_vertex_attribute("color", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2019 "src/vendor/io/pajek-parser.c" +#line 2028 "src/vendor/io/pajek-parser.c" break; case 38: /* vpword: VP_BC parstrval */ -#line 323 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 332 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_vertex_attribute("framecolor", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2027 "src/vendor/io/pajek-parser.c" +#line 2036 "src/vendor/io/pajek-parser.c" break; case 39: /* vpword: VP_LC parstrval */ -#line 326 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 335 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_vertex_attribute("labelcolor", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2035 "src/vendor/io/pajek-parser.c" +#line 2044 "src/vendor/io/pajek-parser.c" break; case 40: /* vpword: parname parstrval */ -#line 329 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 338 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_FINALLY(igraph_free, (yyvsp[-1].dynstr)); if (is_standard_vattr((yyvsp[-1].dynstr))) { @@ -2049,231 +2058,231 @@ YYLTYPE yylloc = yyloc_default; IGRAPH_FREE((yyvsp[-1].dynstr)); IGRAPH_FINALLY_CLEAN(1); } -#line 2053 "src/vendor/io/pajek-parser.c" +#line 2062 "src/vendor/io/pajek-parser.c" break; case 47: /* arcs: "*Arcs line" "end of line" arcsdefs */ -#line 346 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 355 "src/vendor/cigraph/src/io/pajek-parser.y" { context->directed=true; } -#line 2059 "src/vendor/io/pajek-parser.c" +#line 2068 "src/vendor/io/pajek-parser.c" break; case 48: /* arcs: "*Arcs line" number "end of line" arcsdefs */ -#line 347 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 356 "src/vendor/cigraph/src/io/pajek-parser.y" { context->directed=true; } -#line 2065 "src/vendor/io/pajek-parser.c" +#line 2074 "src/vendor/io/pajek-parser.c" break; case 51: /* $@2: %empty */ -#line 351 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 360 "src/vendor/cigraph/src/io/pajek-parser.y" { context->actedge++; } -#line 2071 "src/vendor/io/pajek-parser.c" +#line 2080 "src/vendor/io/pajek-parser.c" break; case 52: /* arcsline: vertex vertex $@2 weight edgeparams "end of line" */ -#line 351 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 360 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-5].intnum)-1)); IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-4].intnum)-1)); } -#line 2079 "src/vendor/io/pajek-parser.c" +#line 2088 "src/vendor/io/pajek-parser.c" break; case 53: /* edges: "*Edges line" "end of line" edgesdefs */ -#line 356 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 365 "src/vendor/cigraph/src/io/pajek-parser.y" { context->directed=0; } -#line 2085 "src/vendor/io/pajek-parser.c" +#line 2094 "src/vendor/io/pajek-parser.c" break; case 54: /* edges: "*Edges line" number "end of line" edgesdefs */ -#line 357 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 366 "src/vendor/cigraph/src/io/pajek-parser.y" { context->directed=0; } -#line 2091 "src/vendor/io/pajek-parser.c" +#line 2100 "src/vendor/io/pajek-parser.c" break; case 57: /* $@3: %empty */ -#line 361 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 370 "src/vendor/cigraph/src/io/pajek-parser.y" { context->actedge++; } -#line 2097 "src/vendor/io/pajek-parser.c" +#line 2106 "src/vendor/io/pajek-parser.c" break; case 58: /* edgesline: vertex vertex $@3 weight edgeparams "end of line" */ -#line 361 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 370 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-5].intnum)-1)); IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[-4].intnum)-1)); } -#line 2105 "src/vendor/io/pajek-parser.c" +#line 2114 "src/vendor/io/pajek-parser.c" break; case 60: /* weight: number */ -#line 366 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 375 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("weight", (yyvsp[0].realnum), context)); } -#line 2113 "src/vendor/io/pajek-parser.c" +#line 2122 "src/vendor/io/pajek-parser.c" break; case 64: /* edgeparam: EP_S number */ -#line 374 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 383 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("arrowsize", (yyvsp[0].realnum), context)); } -#line 2121 "src/vendor/io/pajek-parser.c" +#line 2130 "src/vendor/io/pajek-parser.c" break; case 65: /* edgeparam: EP_W number */ -#line 377 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 386 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("edgewidth", (yyvsp[0].realnum), context)); } -#line 2129 "src/vendor/io/pajek-parser.c" +#line 2138 "src/vendor/io/pajek-parser.c" break; case 66: /* edgeparam: EP_H1 number */ -#line 380 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 389 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("hook1", (yyvsp[0].realnum), context)); } -#line 2137 "src/vendor/io/pajek-parser.c" +#line 2146 "src/vendor/io/pajek-parser.c" break; case 67: /* edgeparam: EP_H2 number */ -#line 383 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 392 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("hook2", (yyvsp[0].realnum), context)); } -#line 2145 "src/vendor/io/pajek-parser.c" +#line 2154 "src/vendor/io/pajek-parser.c" break; case 68: /* edgeparam: EP_A1 number */ -#line 386 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 395 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("angle1", (yyvsp[0].realnum), context)); } -#line 2153 "src/vendor/io/pajek-parser.c" +#line 2162 "src/vendor/io/pajek-parser.c" break; case 69: /* edgeparam: EP_A2 number */ -#line 389 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 398 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("angle2", (yyvsp[0].realnum), context)); } -#line 2161 "src/vendor/io/pajek-parser.c" +#line 2170 "src/vendor/io/pajek-parser.c" break; case 70: /* edgeparam: EP_K1 number */ -#line 392 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 401 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("velocity1", (yyvsp[0].realnum), context)); } -#line 2169 "src/vendor/io/pajek-parser.c" +#line 2178 "src/vendor/io/pajek-parser.c" break; case 71: /* edgeparam: EP_K2 number */ -#line 395 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 404 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("velocity2", (yyvsp[0].realnum), context)); } -#line 2177 "src/vendor/io/pajek-parser.c" +#line 2186 "src/vendor/io/pajek-parser.c" break; case 72: /* edgeparam: EP_AP number */ -#line 398 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 407 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("arrowpos", (yyvsp[0].realnum), context)); } -#line 2185 "src/vendor/io/pajek-parser.c" +#line 2194 "src/vendor/io/pajek-parser.c" break; case 73: /* edgeparam: EP_LP number */ -#line 401 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 410 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("labelpos", (yyvsp[0].realnum), context)); } -#line 2193 "src/vendor/io/pajek-parser.c" +#line 2202 "src/vendor/io/pajek-parser.c" break; case 74: /* edgeparam: EP_LR number */ -#line 404 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 413 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("labelangle", (yyvsp[0].realnum), context)); } -#line 2201 "src/vendor/io/pajek-parser.c" +#line 2210 "src/vendor/io/pajek-parser.c" break; case 75: /* edgeparam: EP_LPHI number */ -#line 407 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 416 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("labelangle2", (yyvsp[0].realnum), context)); } -#line 2209 "src/vendor/io/pajek-parser.c" +#line 2218 "src/vendor/io/pajek-parser.c" break; case 76: /* edgeparam: EP_LA number */ -#line 410 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 419 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("labeldegree", (yyvsp[0].realnum), context)); } -#line 2217 "src/vendor/io/pajek-parser.c" +#line 2226 "src/vendor/io/pajek-parser.c" break; case 77: /* edgeparam: EP_FOS number */ -#line 413 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 422 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_numeric_edge_attribute("fontsize", (yyvsp[0].realnum), context)); } -#line 2225 "src/vendor/io/pajek-parser.c" +#line 2234 "src/vendor/io/pajek-parser.c" break; case 78: /* epword: EP_A parstrval */ -#line 418 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 427 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_edge_attribute("arrowtype", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2233 "src/vendor/io/pajek-parser.c" +#line 2242 "src/vendor/io/pajek-parser.c" break; case 79: /* epword: EP_P parstrval */ -#line 421 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 430 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_edge_attribute("linepattern", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2241 "src/vendor/io/pajek-parser.c" +#line 2250 "src/vendor/io/pajek-parser.c" break; case 80: /* epword: EP_L parstrval */ -#line 424 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 433 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_edge_attribute("label", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2249 "src/vendor/io/pajek-parser.c" +#line 2258 "src/vendor/io/pajek-parser.c" break; case 81: /* epword: EP_LC parstrval */ -#line 427 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 436 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_edge_attribute("labelcolor", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2257 "src/vendor/io/pajek-parser.c" +#line 2266 "src/vendor/io/pajek-parser.c" break; case 82: /* epword: EP_C parstrval */ -#line 430 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 439 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_edge_attribute("color", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2265 "src/vendor/io/pajek-parser.c" +#line 2274 "src/vendor/io/pajek-parser.c" break; case 83: /* epword: EP_FONT parstrval */ -#line 433 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 442 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(add_string_edge_attribute("font", (yyvsp[0].string).str, (yyvsp[0].string).len, context)); } -#line 2273 "src/vendor/io/pajek-parser.c" +#line 2282 "src/vendor/io/pajek-parser.c" break; case 84: /* epword: parname parstrval */ -#line 436 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 445 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_FINALLY(igraph_free, (yyvsp[-1].dynstr)); if (is_standard_eattr((yyvsp[-1].dynstr))) { @@ -2287,68 +2296,68 @@ YYLTYPE yylloc = yyloc_default; IGRAPH_FREE((yyvsp[-1].dynstr)); IGRAPH_FINALLY_CLEAN(1); } -#line 2291 "src/vendor/io/pajek-parser.c" +#line 2300 "src/vendor/io/pajek-parser.c" break; case 85: /* arcslist: "*Arcslist line" "end of line" arcslistlines */ -#line 451 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 460 "src/vendor/cigraph/src/io/pajek-parser.y" { context->directed=true; } -#line 2297 "src/vendor/io/pajek-parser.c" +#line 2306 "src/vendor/io/pajek-parser.c" break; case 91: /* arclistfrom: vertex */ -#line 459 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 468 "src/vendor/cigraph/src/io/pajek-parser.y" { context->actfrom=(yyvsp[0].intnum)-1; } -#line 2303 "src/vendor/io/pajek-parser.c" +#line 2312 "src/vendor/io/pajek-parser.c" break; case 92: /* arclistto: vertex */ -#line 461 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 470 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, context->actfrom)); IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[0].intnum)-1)); } -#line 2312 "src/vendor/io/pajek-parser.c" +#line 2321 "src/vendor/io/pajek-parser.c" break; case 93: /* edgeslist: "*Edgeslist line" "end of line" edgelistlines */ -#line 466 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 475 "src/vendor/cigraph/src/io/pajek-parser.y" { context->directed=0; } -#line 2318 "src/vendor/io/pajek-parser.c" +#line 2327 "src/vendor/io/pajek-parser.c" break; case 99: /* edgelistfrom: vertex */ -#line 474 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 483 "src/vendor/cigraph/src/io/pajek-parser.y" { context->actfrom=(yyvsp[0].intnum)-1; } -#line 2324 "src/vendor/io/pajek-parser.c" +#line 2333 "src/vendor/io/pajek-parser.c" break; case 100: /* edgelistto: vertex */ -#line 476 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 485 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, context->actfrom)); IGRAPH_YY_CHECK(igraph_vector_int_push_back(context->vector, (yyvsp[0].intnum)-1)); } -#line 2333 "src/vendor/io/pajek-parser.c" +#line 2342 "src/vendor/io/pajek-parser.c" break; case 102: /* matrixline: "*Matrix line" */ -#line 485 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 494 "src/vendor/cigraph/src/io/pajek-parser.y" { context->actfrom=0; context->actto=0; context->directed=(context->vcount2==0); } -#line 2342 "src/vendor/io/pajek-parser.c" +#line 2351 "src/vendor/io/pajek-parser.c" break; case 105: /* adjmatrixline: adjmatrixnumbers "end of line" */ -#line 492 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 501 "src/vendor/cigraph/src/io/pajek-parser.y" { context->actfrom++; context->actto=0; } -#line 2348 "src/vendor/io/pajek-parser.c" +#line 2357 "src/vendor/io/pajek-parser.c" break; case 108: /* adjmatrixentry: number */ -#line 496 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 505 "src/vendor/cigraph/src/io/pajek-parser.y" { if ((yyvsp[0].realnum) != 0) { if (context->vcount2==0) { @@ -2366,11 +2375,11 @@ YYLTYPE yylloc = yyloc_default; } context->actto++; } -#line 2370 "src/vendor/io/pajek-parser.c" +#line 2379 "src/vendor/io/pajek-parser.c" break; case 109: /* integer: "number" */ -#line 516 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 525 "src/vendor/cigraph/src/io/pajek-parser.y" { igraph_integer_t val; IGRAPH_YY_CHECK(igraph_i_parse_integer(igraph_pajek_yyget_text(scanner), @@ -2378,11 +2387,11 @@ YYLTYPE yylloc = yyloc_default; &val)); (yyval.intnum)=val; } -#line 2382 "src/vendor/io/pajek-parser.c" +#line 2391 "src/vendor/io/pajek-parser.c" break; case 110: /* number: "number" */ -#line 524 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 533 "src/vendor/cigraph/src/io/pajek-parser.y" { igraph_real_t val; IGRAPH_YY_CHECK(igraph_i_parse_real(igraph_pajek_yyget_text(scanner), @@ -2390,46 +2399,46 @@ YYLTYPE yylloc = yyloc_default; &val)); (yyval.realnum)=val; } -#line 2394 "src/vendor/io/pajek-parser.c" +#line 2403 "src/vendor/io/pajek-parser.c" break; case 111: /* parname: word */ -#line 532 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 541 "src/vendor/cigraph/src/io/pajek-parser.y" { IGRAPH_YY_CHECK(make_dynstr((yyvsp[0].string).str, (yyvsp[0].string).len, &(yyval.dynstr))); } -#line 2402 "src/vendor/io/pajek-parser.c" +#line 2411 "src/vendor/io/pajek-parser.c" break; case 112: /* parstrval: word */ -#line 536 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 545 "src/vendor/cigraph/src/io/pajek-parser.y" { (yyval.string)=(yyvsp[0].string); } -#line 2408 "src/vendor/io/pajek-parser.c" +#line 2417 "src/vendor/io/pajek-parser.c" break; case 113: /* word: "word" */ -#line 538 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 547 "src/vendor/cigraph/src/io/pajek-parser.y" { (yyval.string).str=igraph_pajek_yyget_text(scanner); (yyval.string).len=igraph_pajek_yyget_leng(scanner); } -#line 2415 "src/vendor/io/pajek-parser.c" +#line 2424 "src/vendor/io/pajek-parser.c" break; case 114: /* word: "number" */ -#line 540 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 549 "src/vendor/cigraph/src/io/pajek-parser.y" { (yyval.string).str=igraph_pajek_yyget_text(scanner); (yyval.string).len=igraph_pajek_yyget_leng(scanner); } -#line 2422 "src/vendor/io/pajek-parser.c" +#line 2431 "src/vendor/io/pajek-parser.c" break; case 115: /* word: "quoted string" */ -#line 542 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 551 "src/vendor/cigraph/src/io/pajek-parser.y" { (yyval.string).str=igraph_pajek_yyget_text(scanner)+1; (yyval.string).len=igraph_pajek_yyget_leng(scanner)-2; } -#line 2429 "src/vendor/io/pajek-parser.c" +#line 2438 "src/vendor/io/pajek-parser.c" break; -#line 2433 "src/vendor/io/pajek-parser.c" +#line 2442 "src/vendor/io/pajek-parser.c" default: break; } @@ -2658,7 +2667,7 @@ YYLTYPE yylloc = yyloc_default; return yyresult; } -#line 545 "src/vendor/cigraph/src/io/pajek-parser.y" +#line 554 "src/vendor/cigraph/src/io/pajek-parser.y" int igraph_pajek_yyerror(YYLTYPE* locp,