[med-svn] [Git][med-team/igraph][upstream] 2 commits: New upstream version 0.9.8

Jérôme Benoit (@calculus) gitlab at salsa.debian.org
Sat Apr 9 14:48:49 BST 2022



Jérôme Benoit pushed to branch upstream at Debian Med / igraph


Commits:
fff966a1 by Jerome Benoit at 2022-04-09T15:01:23+02:00
New upstream version 0.9.8
- - - - -
51607d74 by Jerome Benoit at 2022-04-09T15:04:46+02:00
New upstream version 0.9.8+ds
- - - - -


27 changed files:

- CHANGELOG.md
- CMakeLists.txt
- IGRAPH_VERSION
- interfaces/functions.yaml
- src/CMakeLists.txt
- src/cliques/glet.c
- src/community/walktrap/walktrap_communities.cpp
- src/connectivity/components.c
- − src/core/hashtable.c
- − src/core/hashtable.h
- src/graph/adjlist.c
- src/graph/visitors.c
- src/internal/glpk_support.c
- src/internal/glpk_support.h
- src/isomorphism/bliss/graph.cc
- src/misc/bipartite.c
- src/properties/basic_properties.c
- tests/CMakeLists.txt
- tests/unit/bfs.c
- tests/unit/bfs.out
- tests/unit/community_walktrap.c
- tests/unit/community_walktrap.out
- − tests/unit/hashtable.c
- − tests/unit/hashtable.out
- tests/unit/igraph_diversity.c
- tests/unit/igraph_diversity.out
- tests/unit/igraph_hrg3.c


Changes:

=====================================
CHANGELOG.md
=====================================
@@ -1,5 +1,18 @@
 # igraph C library changelog
 
+## [0.9.8] - 2022-04-08
+
+### Fixed
+
+ - Assertion failure in `igraph_bfs()` when an empty `roots` or `restricted` vector was provided.
+ - `igraph_diversity()` now returns 0 for degree-1 vertices. Previously it incorrectly returned NaN or +-Inf depending on roundoff errors.
+ - `igraph_community_walktrap()` does not crash any more when provided with
+   `modularity=NULL` and `membership=NULL`.
+
+### Other
+
+ - Documentation improvements.
+
 ## [0.9.7] - 2022-03-16
 
 ### Changed
@@ -31,7 +44,7 @@
 ### Other
 
  - The C attribute handler now verifies attribute types when retrieving attributes.
- - Documentation improvements
+ - Documentation improvements.
 
 ## [0.9.6] - 2022-01-05
 
@@ -552,7 +565,8 @@
  - Provide proper support for Windows, using `__declspec(dllexport)` and `__declspec(dllimport)` for `DLL`s and static usage by using `#define IGRAPH_STATIC 1`.
  - Provided integer versions of `dqueue` and `stack` data types.
 
-[Unreleased]: https://github.com/igraph/igraph/compare/0.9.7..HEAD
+[Unreleased]: https://github.com/igraph/igraph/compare/0.9.8..HEAD
+[0.9.8]: https://github.com/igraph/igraph/compare/0.9.7...0.9.8
 [0.9.7]: https://github.com/igraph/igraph/compare/0.9.6...0.9.7
 [0.9.6]: https://github.com/igraph/igraph/compare/0.9.5...0.9.6
 [0.9.5]: https://github.com/igraph/igraph/compare/0.9.4...0.9.5


=====================================
CMakeLists.txt
=====================================
@@ -101,7 +101,7 @@ if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME AND IGRAPH_ENABLE_CODE_COVERAGE)
     EXECUTABLE "${CMAKE_COMMAND}" "--build" "${PROJECT_BINARY_DIR}" "--target" "check"
     # Generated files are excluded; apparently the CodeCoverage script has some
     # problems with them. Yes, the exclusion is correct, it refers to a nonexistent
-    # directory that somehow gets into the coverage resolts. /Applications is for
+    # directory that somehow gets into the coverage results. /Applications is for
     # macOS -- it excludes files from the macOS SDK.
     EXCLUDE "io/*.l" "io/parsers/*" "/Applications/Xcode*" "examples/*" "tests/*"
   )


=====================================
IGRAPH_VERSION
=====================================
@@ -1 +1 @@
-0.9.7
\ No newline at end of file
+0.9.8
\ No newline at end of file


=====================================
interfaces/functions.yaml
=====================================
@@ -689,14 +689,15 @@ igraph_is_mutual:
     DEPS: es ON graph
 
 igraph_maximum_cardinality_search:
-    PARAMS: GRAPH graph, OUT VERTEXSET alpha, OUT VECTORM1_OR_0 alpham1
-    DEPS: alpha ON graph, alpham1 ON graph
+    PARAMS: GRAPH graph, OPTIONAL OUT VECTORM1 alpha, OPTIONAL OUT VERTEXSET alpham1
+    DEPS: alpham1 ON graph
 
 igraph_is_chordal:
     PARAMS: |-
-        GRAPH graph, VECTORM1_OR_0 alpha=NULL, VECTORM1_OR_0 alpham1=NULL,
+        GRAPH graph, VECTORM1 alpha=NULL, OPTIONAL VECTORM1 alpham1=NULL,
         OPTIONAL OUT BOOLEAN chordal, OUT VECTORM1_OR_0 fillin,
         OUT GRAPH_OR_0 newgraph
+    DEPS: alpham1 ON graph
 
 igraph_avg_nearest_neighbor_degree:
     PARAMS: |-
@@ -724,9 +725,12 @@ igraph_centralization_degree:
         BOOLEAN normalized=True
 
 igraph_centralization_degree_tmax:
+    # The general consensus is that the 'loops' argument of this function
+    # should not have a default value; see this comment from @torfason:
+    # https://github.com/igraph/rigraph/issues/369#issuecomment-939893681
     PARAMS: |-
         GRAPH_OR_0 graph=NULL, INTEGER nodes=0, NEIMODE mode=ALL,
-        BOOLEAN loops=False, OUT REAL res
+        BOOLEAN loops, OUT REAL res
 
 igraph_centralization_betweenness:
     PARAMS: |-
@@ -1654,6 +1658,15 @@ igraph_mincut:
         GRAPH graph, OUT REAL value, OUT VECTORM1 partition1,
         OUT VECTORM1 partition2, OUT VECTORM1 cut, VECTOR_OR_0 capacity
 
+igraph_st_mincut:
+    PARAMS: |-
+        GRAPH graph, OUT REAL value, OUT VECTORM1_OR_0 cut,
+        OPTIONAL OUT VERTEXSET partition1, OPTIONAL OUT VERTEXSET partition2,
+        VERTEX source, VERTEX target, EDGECAPACITY capacity=NULL
+    DEPS: |-
+        capacity ON graph, source ON graph, target ON graph,
+        partition1 ON graph, partition2 ON graph, cut ON graph
+
 igraph_st_vertex_connectivity:
     PARAMS: |-
         GRAPH graph, OUT INTEGER res, VERTEX source, VERTEX target,
@@ -1690,10 +1703,10 @@ igraph_cohesion:
 
 igraph_dominator_tree:
     PARAMS: |-
-        GRAPH graph, VERTEX root, OUT VERTEXSET dom,
+        GRAPH graph, VERTEX root, OUT VECTORM1 dom,
         OUT GRAPH_OR_0 domtree, OUT VERTEXSET leftout,
         NEIMODE mode=OUT
-    DEPS: root ON graph, dom ON graph, leftout ON graph
+    DEPS: root ON graph, leftout ON graph
 
 igraph_all_st_cuts:
     PARAMS: |-


=====================================
src/CMakeLists.txt
=====================================
@@ -43,7 +43,6 @@ add_library(
   core/estack.c
   core/fixed_vectorlist.c
   core/grid.c
-  core/hashtable.c
   core/heap.c
   core/indheap.c
   core/interruption.c


=====================================
src/cliques/glet.c
=====================================
@@ -82,25 +82,19 @@ static void igraph_i_subclique_next_free(void *ptr) {
     int i;
     if (data->resultids) {
         for (i = 0; i < data->nc; i++) {
-            if (data->resultids + i) {
-                igraph_vector_int_destroy(data->resultids + i);
-            }
+            igraph_vector_int_destroy(&data->resultids[i]);
         }
         IGRAPH_FREE(data->resultids);
     }
     if (data->result) {
         for (i = 0; i < data->nc; i++) {
-            if (data->result + i) {
-                igraph_destroy(data->result + i);
-            }
+            igraph_destroy(&data->result[i]);
         }
         IGRAPH_FREE(data->result);
     }
     if (data->resultweights) {
         for (i = 0; i < data->nc; i++) {
-            if (data->resultweights + i) {
-                igraph_vector_destroy(data->resultweights + i);
-            }
+            igraph_vector_destroy(&data->resultweights[i]);
         }
         IGRAPH_FREE(data->resultweights);
     }


=====================================
src/community/walktrap/walktrap_communities.cpp
=====================================
@@ -488,7 +488,10 @@ Communities::Communities(Graph* graph, int random_walks_length,
         Q += (communities[i].internal_weight - communities[i].total_weight * communities[i].total_weight / G->total_weight) / G->total_weight;
       }
     }
-    VECTOR(*modularity)[mergeidx] = Q;
+
+    if (modularity) {
+        VECTOR(*modularity)[mergeidx] = Q;
+    }
 }
 
 Communities::~Communities() {


=====================================
src/connectivity/components.c
=====================================
@@ -345,7 +345,7 @@ static int igraph_is_connected_weak(const igraph_t *graph, igraph_bool_t *res);
  * definition. This behaviour changed in igraph 0.9; earlier versions assumed
  * that the null graph is connected. See the following issue on Github for the
  * argument that led us to change the definition:
- * https://github.com/igraph/igraph/issues/1538
+ * https://github.com/igraph/igraph/issues/1539
  *
  * \param graph The graph object to analyze.
  * \param res Pointer to a logical variable, the result will be stored
@@ -369,7 +369,7 @@ int igraph_is_connected(const igraph_t *graph, igraph_bool_t *res,
     long int no_of_nodes = igraph_vcount(graph);
 
     if (no_of_nodes == 0) {
-        /* Changed in igraph 0.9; see https://github.com/igraph/igraph/issues/1538
+        /* Changed in igraph 0.9; see https://github.com/igraph/igraph/issues/1539
          * for the reasoning behind the change */
         *res = 0;
         return IGRAPH_SUCCESS;


=====================================
src/core/hashtable.c deleted
=====================================
@@ -1,129 +0,0 @@
-/* -*- mode: C -*-  */
-/*
-   IGraph library.
-   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   334 Harvard street, Cambridge, MA 02139 USA
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA
-
-*/
-
-#include "igraph_types.h"
-#include "igraph_memory.h"
-#include "igraph_error.h"
-
-#include "core/hashtable.h"
-
-#include <string.h>
-
-int igraph_hashtable_init(igraph_hashtable_t *ht) {
-    IGRAPH_CHECK(igraph_trie_init(&ht->keys, 1));
-    IGRAPH_FINALLY(igraph_trie_destroy, &ht->keys);
-    IGRAPH_CHECK(igraph_strvector_init(&ht->elements, 0));
-    IGRAPH_FINALLY(igraph_strvector_destroy, &ht->elements);
-    IGRAPH_CHECK(igraph_strvector_init(&ht->defaults, 0));
-
-    IGRAPH_FINALLY_CLEAN(2);
-    return 0;
-}
-
-void igraph_hashtable_destroy(igraph_hashtable_t *ht) {
-    igraph_trie_destroy(&ht->keys);
-    igraph_strvector_destroy(&ht->elements);
-    igraph_strvector_destroy(&ht->defaults);
-}
-
-/* Note: may leave the hash table in an inconsistent state if a new
-   element is added, but this is not a big problem, since while the
-   defaults, or the defaults plus the elements may contain more elements
-   than the keys trie, but the data is always retrieved based on the trie
-*/
-
-int igraph_hashtable_addset(igraph_hashtable_t *ht,
-                            const char *key, const char *def,
-                            const char *elem) {
-    long int size = igraph_trie_size(&ht->keys);
-    long int newid;
-    IGRAPH_CHECK(igraph_trie_get(&ht->keys, key, &newid));
-
-    if (newid == size) {
-        /* this is a new element */
-        IGRAPH_CHECK(igraph_strvector_resize(&ht->defaults, newid + 1));
-        IGRAPH_CHECK(igraph_strvector_resize(&ht->elements, newid + 1));
-        IGRAPH_CHECK(igraph_strvector_set(&ht->defaults, newid, def));
-        IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, elem));
-    } else {
-        /* set an already existing element */
-        IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, elem));
-    }
-
-    return 0;
-}
-
-/* Previous comment also applies here */
-
-int igraph_hashtable_addset2(igraph_hashtable_t *ht,
-                             const char *key, const char *def,
-                             const char *elem, int elemlen) {
-    long int size = igraph_trie_size(&ht->keys);
-    long int newid;
-    char *tmp;
-
-    IGRAPH_CHECK(igraph_trie_get(&ht->keys, key, &newid));
-
-    tmp = IGRAPH_CALLOC(elemlen + 1, char);
-    if (tmp == 0) {
-        IGRAPH_ERROR("cannot add element to hash table", IGRAPH_ENOMEM);
-    }
-    IGRAPH_FINALLY(igraph_free, tmp);
-    strncpy(tmp, elem, elemlen);
-    tmp[elemlen] = '\0';
-
-    if (newid == size) {
-        IGRAPH_CHECK(igraph_strvector_resize(&ht->defaults, newid + 1));
-        IGRAPH_CHECK(igraph_strvector_resize(&ht->elements, newid + 1));
-        IGRAPH_CHECK(igraph_strvector_set(&ht->defaults, newid, def));
-        IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, tmp));
-    } else {
-        IGRAPH_CHECK(igraph_strvector_set(&ht->elements, newid, tmp));
-    }
-
-    IGRAPH_FREE(tmp);
-    IGRAPH_FINALLY_CLEAN(1);
-
-    return 0;
-}
-
-int igraph_hashtable_get(igraph_hashtable_t *ht,
-                         const char *key, char **elem) {
-    long int newid;
-    IGRAPH_CHECK(igraph_trie_get(&ht->keys, key, &newid));
-
-    igraph_strvector_get(&ht->elements, newid, elem);
-
-    return 0;
-}
-
-int igraph_hashtable_reset(igraph_hashtable_t *ht) {
-    igraph_strvector_destroy(&ht->elements);
-    IGRAPH_CHECK(igraph_strvector_copy(&ht->elements, &ht->defaults));
-    return 0;
-}
-
-int igraph_hashtable_getkeys(igraph_hashtable_t *ht,
-                             const igraph_strvector_t **sv) {
-    return igraph_trie_getkeys(&ht->keys, sv);
-}


=====================================
src/core/hashtable.h deleted
=====================================
@@ -1,58 +0,0 @@
-/* -*- mode: C -*-  */
-/*
-   IGraph library.
-   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
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA
-
-*/
-
-#ifndef IGRAPH_CORE_HASHTABLE_H
-#define IGRAPH_CORE_HASHTABLE_H
-
-#include "igraph_decls.h"
-#include "igraph_types.h"
-#include "igraph_strvector.h"
-
-#include "core/trie.h"
-
-__BEGIN_DECLS
-
-/* string -> string hash table */
-
-typedef struct igraph_hashtable_t {
-    igraph_trie_t keys;
-    igraph_strvector_t elements;
-    igraph_strvector_t defaults;
-} igraph_hashtable_t;
-
-IGRAPH_PRIVATE_EXPORT int igraph_hashtable_init(igraph_hashtable_t *ht);
-IGRAPH_PRIVATE_EXPORT void igraph_hashtable_destroy(igraph_hashtable_t *ht);
-IGRAPH_PRIVATE_EXPORT int igraph_hashtable_addset(igraph_hashtable_t *ht,
-                                                  const char *key, const char *def,
-                                                  const char *elem);
-IGRAPH_PRIVATE_EXPORT int igraph_hashtable_addset2(igraph_hashtable_t *ht,
-                                                   const char *key, const char *def,
-                                                   const char *elem, int elemlen);
-IGRAPH_PRIVATE_EXPORT int igraph_hashtable_get(igraph_hashtable_t *ht,
-                                               const char *key, char **elem);
-IGRAPH_PRIVATE_EXPORT int igraph_hashtable_getkeys(igraph_hashtable_t *ht,
-                                                   const igraph_strvector_t **sv);
-IGRAPH_PRIVATE_EXPORT int igraph_hashtable_reset(igraph_hashtable_t *ht);
-
-__END_DECLS
-
-#endif


=====================================
src/graph/adjlist.c
=====================================
@@ -297,9 +297,7 @@ int igraph_adjlist_init_complementer(const igraph_t *graph,
 void igraph_adjlist_destroy(igraph_adjlist_t *al) {
     long int i;
     for (i = 0; i < al->length; i++) {
-        if (&al->adjs[i]) {
-            igraph_vector_int_destroy(&al->adjs[i]);
-        }
+        igraph_vector_int_destroy(&al->adjs[i]);
     }
     IGRAPH_FREE(al->adjs);
 }


=====================================
src/graph/visitors.c
=====================================
@@ -122,7 +122,7 @@ int igraph_bfs(const igraph_t *graph,
         IGRAPH_ERROR("Invalid root vertex in BFS", IGRAPH_EINVAL);
     }
 
-    if (roots) {
+    if (roots && noroots > 0) {
         igraph_real_t min, max;
         igraph_vector_minmax(roots, &min, &max);
         if (min < 0 || max >= no_of_nodes) {
@@ -130,7 +130,7 @@ int igraph_bfs(const igraph_t *graph,
         }
     }
 
-    if (restricted) {
+    if (restricted && igraph_vector_size(restricted) > 0) {
         igraph_real_t min, max;
         igraph_vector_minmax(restricted, &min, &max);
         if (min < 0 || max >= no_of_nodes) {


=====================================
src/internal/glpk_support.c
=====================================
@@ -34,6 +34,16 @@
 
 IGRAPH_THREAD_LOCAL igraph_i_glpk_error_info_t igraph_i_glpk_error_info;
 
+/* glp_at_error() was added in GLPK 4.57. Due to the R interface, we need to
+ * support ancient GLPK versions like GLPK 4.38 so we need to guard the
+ * invocation of glp_at_error(). Note that this is a temporary workaround only
+ * for sake of supporting R 4.1, so it is enabled only if USING_R is defined */
+#ifdef USING_R
+#  define HAS_GLP_AT_ERROR (GLP_MAJOR_VERSION > 4 || (GLP_MAJOR_VERSION == 4 && GLP_MINOR_VERSION >= 57))
+#else
+#  define HAS_GLP_AT_ERROR 1
+#endif
+
 int igraph_i_glpk_terminal_hook(void *info, const char *s) {
     IGRAPH_UNUSED(info);
 
@@ -45,6 +55,7 @@ int igraph_i_glpk_terminal_hook(void *info, const char *s) {
            and the error_hook. */
         igraph_i_glpk_error_info.is_interrupted = 1;
         glp_error("GLPK was interrupted."); /* This dummy message is never printed */
+#if HAS_GLP_AT_ERROR
     } else if (glp_at_error()) {
         /* Copy the error messages into a buffer for later reporting */
         /* We must use glp_at_error() instead of igraph_i_glpk_error_info.is_error
@@ -55,6 +66,7 @@ int igraph_i_glpk_terminal_hook(void *info, const char *s) {
             *(igraph_i_glpk_error_info.msg_ptr++) = *(s++);
         }
         *igraph_i_glpk_error_info.msg_ptr = '\0';
+#endif
     }
 
     return 1; /* Non-zero return value signals to GLPK not to print to the terminal */


=====================================
src/internal/glpk_support.h
=====================================
@@ -126,6 +126,10 @@ void igraph_i_glp_delete_prob(glp_prob *p);
                     } \
                     *igraph_i_glpk_error_info.msg_ptr = '\0'; \
                     igraph_error(igraph_i_glpk_error_info.msg, IGRAPH_FILE_BASENAME, __LINE__, IGRAPH_EGLP); \
+                } else if (igraph_i_glpk_error_info.is_error) { \
+                    /* This branch can never be reached unless compiled with USING_R and using */ \
+                    /* the hack to support pre-4.57 GLPK versions. See comments in glpk_support.c. */ \
+                    igraph_error("Error while running GLPK solver.", IGRAPH_FILE_BASENAME, __LINE__, IGRAPH_EGLP); \
                 } \
                 return IGRAPH_EGLP; \
             } \


=====================================
src/isomorphism/bliss/graph.cc
=====================================
@@ -604,7 +604,7 @@ public:
   unsigned int cr_cep_index;
   unsigned int cr_level;
 
-  bool needs_long_prune;
+  bool needs_long_prune = false; /* igraph-specific patch: initialize to false to silence UBSan */
   unsigned int long_prune_begin;
   std::set<unsigned int, std::less<unsigned int> > long_prune_redundant;
 
@@ -1499,9 +1499,6 @@ AbstractGraph::search(const bool canonical,
           child_node.cr_cep_stack_size = cr_cep_stack.size();
           child_node.cr_cep_index = cr_cep_index;
 
-          /* Initialize needs_long_prune to prevent a gcc-ubsan warning */
-          child_node.needs_long_prune = true;
-
           search_stack.push_back(child_node);
           continue;
         }


=====================================
src/misc/bipartite.c
=====================================
@@ -524,7 +524,7 @@ int igraph_create_bipartite(igraph_t *graph, const igraph_vector_bool_t *types,
         igraph_vector_minmax(edges, &min_edge, &max_edge);
     }
     if (min_edge < 0 || max_edge >= no_of_nodes) {
-        IGRAPH_ERROR("Invalid (negative) vertex id", IGRAPH_EINVVID);
+        IGRAPH_ERROR("Invalid (negative or too large) vertex id", IGRAPH_EINVVID);
     }
 
     /* Check bipartiteness */


=====================================
src/properties/basic_properties.c
=====================================
@@ -107,7 +107,8 @@ int igraph_density(const igraph_t *graph, igraph_real_t *res,
  * where p[i,j]=w[i,j]/sum(w[i,l], l=1..k[i]),  k[i] is the (total)
  * degree of vertex i, and w[i,j] is the weight of the edge(s) between
  * vertex i and j. The diversity of isolated vertices will be NaN
- * (not-a-number).
+ * (not-a-number), while that of vertices with a single connection
+ * will be zero.
  *
  * </para><para>
  * The measure works only if the graph is undirected and has no multiple edges.
@@ -117,7 +118,7 @@ int igraph_density(const igraph_t *graph, igraph_real_t *res,
  *
  * \param graph The undirected input graph.
  * \param weights The edge weights, in the order of the edge ids, must
- *    have appropriate length.
+ *    have appropriate length. Weights must be non-negative.
  * \param res An initialized vector, the results are stored here.
  * \param vids Vertex selector that specifies the vertices which to calculate
  *    the measure.
@@ -129,13 +130,11 @@ int igraph_density(const igraph_t *graph, igraph_real_t *res,
 int igraph_diversity(const igraph_t *graph, const igraph_vector_t *weights,
                      igraph_vector_t *res, const igraph_vs_t vids) {
 
-    int no_of_nodes = igraph_vcount(graph);
-    int no_of_edges = igraph_ecount(graph);
+    long int no_of_edges = igraph_ecount(graph);
+    long int k, i;
     igraph_vector_t incident;
-    igraph_vit_t vit;
-    igraph_real_t s, ent, w;
-    int i, j, k;
     igraph_bool_t has_multiple;
+    igraph_vit_t vit;
 
     if (igraph_is_directed(graph)) {
         IGRAPH_ERROR("Diversity measure works with undirected graphs only.", IGRAPH_EINVAL);
@@ -154,48 +153,65 @@ int igraph_diversity(const igraph_t *graph, const igraph_vector_t *weights,
         IGRAPH_ERROR("Diversity measure works only if the graph has no multiple edges.", IGRAPH_EINVAL);
     }
 
+    if (no_of_edges > 0) {
+        igraph_real_t minweight = igraph_vector_min(weights);
+        if (minweight < 0) {
+            IGRAPH_ERROR("Weight vector must be non-negative.", IGRAPH_EINVAL);
+        } else if (igraph_is_nan(minweight)) {
+            IGRAPH_ERROR("Weight vector must not contain NaN values.", IGRAPH_EINVAL);
+        }
+    }
+
     IGRAPH_VECTOR_INIT_FINALLY(&incident, 10);
 
-    if (igraph_vs_is_all(&vids)) {
-        IGRAPH_CHECK(igraph_vector_resize(res, no_of_nodes));
-        for (i = 0; i < no_of_nodes; i++) {
-            s = ent = 0.0;
-            IGRAPH_CHECK(igraph_incident(graph, &incident, i, /*mode=*/ IGRAPH_ALL));
-            for (j = 0, k = (int) igraph_vector_size(&incident); j < k; j++) {
-                w = VECTOR(*weights)[(long int)VECTOR(incident)[j]];
-                s += w;
-                ent += (w * log(w));
-            }
-            VECTOR(*res)[i] = (log(s) - ent / s) / log(k);
-        }
-    } else {
-        IGRAPH_CHECK(igraph_vector_resize(res, 0));
-        IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
-        IGRAPH_FINALLY(igraph_vit_destroy, &vit);
-
-        for (IGRAPH_VIT_RESET(vit), i = 0;
-             !IGRAPH_VIT_END(vit);
-             IGRAPH_VIT_NEXT(vit), i++) {
-            long int v = IGRAPH_VIT_GET(vit);
-            s = ent = 0.0;
-            IGRAPH_CHECK(igraph_incident(graph, &incident, (igraph_integer_t) v,
-                                         /*mode=*/ IGRAPH_ALL));
-            for (j = 0, k = (int) igraph_vector_size(&incident); j < k; j++) {
-                w = VECTOR(*weights)[(long int)VECTOR(incident)[j]];
+    IGRAPH_CHECK(igraph_vit_create(graph, vids, &vit));
+    IGRAPH_FINALLY(igraph_vit_destroy, &vit);
+
+    igraph_vector_clear(res);
+    IGRAPH_CHECK(igraph_vector_reserve(res, IGRAPH_VIT_SIZE(vit)));
+
+    for (IGRAPH_VIT_RESET(vit); !IGRAPH_VIT_END(vit); IGRAPH_VIT_NEXT(vit)) {
+        igraph_real_t d;
+        long int v = IGRAPH_VIT_GET(vit);
+
+        IGRAPH_CHECK(igraph_incident(graph, &incident, v, /*mode=*/ IGRAPH_ALL));
+        k = igraph_vector_size(&incident); /* degree */
+
+        /*
+         * Non-normalized diversity is defined as
+         * d = -sum_i w_i/s log (w_i/s)
+         * where s = sum_i w_i. In order to avoid two passes through the w vector,
+         * we use the equivalent formulation of
+         * d = log s - (sum_i w_i log w_i) / s
+         * However, this formulation may not give an exact 0.0 for some w when k=1,
+         * due to roundoff errors (examples: w=3 or w=7). For this reason, we
+         * special-case the computation for k=1 even for the unnormalized diversity
+         * insted of just setting the normalization factor to 1 for this case.
+         */
+        if (k == 0) {
+            d = IGRAPH_NAN;
+        } else if (k == 1) {
+            if (VECTOR(*weights)[0] > 0) d = 0.0; /* s > 0 */
+            else d = IGRAPH_NAN; /* s == 0 */
+        } else {
+            igraph_real_t s = 0.0, ent = 0.0;
+            for (i = 0; i < k; i++) {
+                igraph_real_t w = VECTOR(*weights)[(long int)VECTOR(incident)[i]];
+                if (w == 0) continue;
                 s += w;
                 ent += (w * log(w));
             }
-            IGRAPH_CHECK(igraph_vector_push_back(res, (log(s) - ent / s) / log(k)));
+            d = (log(s) - ent / s) / log(k);
         }
 
-        igraph_vit_destroy(&vit);
-        IGRAPH_FINALLY_CLEAN(1);
+        igraph_vector_push_back(res, d); /* reserved */
     }
 
+    igraph_vit_destroy(&vit);
     igraph_vector_destroy(&incident);
-    IGRAPH_FINALLY_CLEAN(1);
+    IGRAPH_FINALLY_CLEAN(2);
 
-    return 0;
+    return IGRAPH_SUCCESS;
 }
 
 /**


=====================================
tests/CMakeLists.txt
=====================================
@@ -113,7 +113,6 @@ add_legacy_tests(
   2wheap
   cutheap
   d_indheap
-  hashtable
   marked_queue
   set
   trie


=====================================
tests/unit/bfs.c
=====================================
@@ -127,6 +127,15 @@ int main() {
                0, 0, 0, 0, 0, 0, &bfs_callback, 0);
     printf(" )\n");
 
+    /* Empty root vertex vector */
+
+    igraph_vector_clear(&roots);
+    printf("(");
+    igraph_bfs(&graph, /*root=*/ -1, &roots, /*neimode=*/ IGRAPH_OUT,
+               /*unreachable=*/ 0, &restricted,
+               0, 0, 0, 0, 0, 0, &bfs_callback, 0);
+    printf(" )\n");
+
     igraph_vector_destroy(&roots);
     igraph_vector_destroy(&restricted);
     igraph_destroy(&graph);


=====================================
tests/unit/bfs.out
=====================================
@@ -10,3 +10,4 @@
 ( 5 6 7 8 9 10 11 19 12 18 13 17 14 16 15 )
 ( )
 ( 6 5 7 8 9 )
+( )


=====================================
tests/unit/community_walktrap.c
=====================================
@@ -56,6 +56,17 @@ int main() {
   igraph_vector_destroy(&membership);
   igraph_vector_destroy(&modularity);
   igraph_matrix_destroy(&merges);
+
+  /* Test the case when modularity=0 and membership=0 as this caused a crash in
+   * the R interface, see https://github.com/igraph/rigraph/issues/289 */
+
+  igraph_matrix_init(&merges, 0, 0);
+
+  igraph_community_walktrap(&graph, NULL, 4, &merges, NULL, NULL);
+  printf("Merges:\n");
+  igraph_matrix_print(&merges);
+  igraph_matrix_destroy(&merges);
+
   igraph_destroy(&graph);
 
   VERIFY_FINALLY_STACK();


=====================================
tests/unit/community_walktrap.out
=====================================
@@ -3,3 +3,6 @@ Merges:
 0 3
 Modularity: -0.333333 -0.222222 0
 Membership: 0 0 0
+Merges:
+1 2
+0 3


=====================================
tests/unit/hashtable.c deleted
=====================================
@@ -1,133 +0,0 @@
-/* -*- mode: C -*-  */
-/*
-   IGraph library.
-   Copyright (C) 2006-2012  Gabor Csardi <csardi.gabor at gmail.com>
-   334 Harvard st, Cambridge MA, 02139 USA
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
-   (at your option) any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc.,  51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301 USA
-
-*/
-
-#include <igraph.h>
-#include "core/hashtable.h"
-
-#include "test_utilities.inc"
-
-int main() {
-
-    igraph_hashtable_t ht;
-    char *str;
-    const igraph_strvector_t *keys;
-    long int i;
-
-    /* init and destroy */
-    igraph_hashtable_init(&ht);
-    igraph_hashtable_destroy(&ht);
-
-    /* init, add some elements and destroy */
-    igraph_hashtable_init(&ht);
-    igraph_hashtable_addset(&ht, "color", "green", "red");
-    igraph_hashtable_addset(&ht, "size", "", "4");
-    igraph_hashtable_addset(&ht, "color", "", "grey");
-    igraph_hashtable_addset(&ht, "shape", "", "circle");
-    igraph_hashtable_addset(&ht, "shape", "", "diamond");
-    igraph_hashtable_destroy(&ht);
-
-    /* reset */
-    igraph_hashtable_init(&ht);
-    igraph_hashtable_addset(&ht, "color", "green", "red");
-    igraph_hashtable_addset(&ht, "size", "", "4");
-    igraph_hashtable_addset(&ht, "color", "", "grey");
-    igraph_hashtable_addset(&ht, "shape", "", "circle");
-    igraph_hashtable_addset(&ht, "shape", "", "diamond");
-    igraph_hashtable_reset(&ht);
-    igraph_hashtable_addset(&ht, "color", "green", "red");
-    igraph_hashtable_addset(&ht, "size", "", "4");
-    igraph_hashtable_addset(&ht, "color", "", "grey");
-    igraph_hashtable_addset(&ht, "shape", "", "circle");
-    igraph_hashtable_addset(&ht, "shape", "", "diamond");
-    igraph_hashtable_destroy(&ht);
-
-    /* Check semantics */
-    igraph_hashtable_init(&ht);
-    igraph_hashtable_addset(&ht, "color", "green", "red");
-    igraph_hashtable_addset(&ht, "size", "", "4");
-    igraph_hashtable_addset(&ht, "color", "", "grey");
-    igraph_hashtable_addset(&ht, "shape", "", "circle");
-    igraph_hashtable_addset(&ht, "shape", "", "diamond");
-
-    igraph_hashtable_get(&ht, "color", &str);
-    printf("color: %s\n", str);
-    igraph_hashtable_get(&ht, "size", &str);
-    printf("size: %s\n", str);
-    igraph_hashtable_get(&ht, "shape", &str);
-    printf("shape: %s\n", str);
-
-    igraph_hashtable_reset(&ht);
-
-    igraph_hashtable_get(&ht, "color", &str);
-    printf("color: %s\n", str);
-    igraph_hashtable_get(&ht, "size", &str);
-    printf("size: %s\n", str);
-    igraph_hashtable_get(&ht, "shape", &str);
-    printf("shape: %s\n", str);
-
-    igraph_hashtable_getkeys(&ht, &keys);
-    for (i = 0; i < igraph_strvector_size(keys); i++) {
-        igraph_strvector_get(keys, i, &str);
-        printf("%s ", str);
-    }
-    printf("\n");
-
-    igraph_hashtable_destroy(&ht);
-
-    /* addset2 */
-    igraph_hashtable_init(&ht);
-    igraph_hashtable_addset2(&ht, "color", "green", "redddd", 3);
-    igraph_hashtable_addset2(&ht, "size", "", "4111", 1);
-    igraph_hashtable_addset2(&ht, "color", "", "greysdsdf", 4);
-    igraph_hashtable_addset2(&ht, "shape", "", "circle", 6);
-    igraph_hashtable_addset(&ht, "shape", "", "diamond");
-
-    igraph_hashtable_get(&ht, "color", &str);
-    printf("color: %s\n", str);
-    igraph_hashtable_get(&ht, "size", &str);
-    printf("size: %s\n", str);
-    igraph_hashtable_get(&ht, "shape", &str);
-    printf("shape: %s\n", str);
-
-    igraph_hashtable_reset(&ht);
-
-    igraph_hashtable_get(&ht, "color", &str);
-    printf("color: %s\n", str);
-    igraph_hashtable_get(&ht, "size", &str);
-    printf("size: %s\n", str);
-    igraph_hashtable_get(&ht, "shape", &str);
-    printf("shape: %s\n", str);
-
-    igraph_hashtable_getkeys(&ht, &keys);
-    for (i = 0; i < igraph_strvector_size(keys); i++) {
-        igraph_strvector_get(keys, i, &str);
-        printf("%s ", str);
-    }
-    printf("\n");
-
-    igraph_hashtable_destroy(&ht);
-
-    VERIFY_FINALLY_STACK();
-
-    return 0;
-}


=====================================
tests/unit/hashtable.out deleted
=====================================
@@ -1,14 +0,0 @@
-color: grey
-size: 4
-shape: diamond
-color: green
-size: 
-shape: 
-color size shape 
-color: grey
-size: 4
-shape: diamond
-color: green
-size: 
-shape: 
-color size shape 


=====================================
tests/unit/igraph_diversity.c
=====================================
@@ -44,21 +44,38 @@ int main() {
     igraph_vector_destroy(&weights);
     igraph_destroy(&g);
 
+    /* degree-one vertices */
+    igraph_tree(&g, 10, 2, IGRAPH_TREE_UNDIRECTED);
+    igraph_vector_init_seq(&weights, 1, igraph_ecount(&g));
+
+    printf("Tree (having degree-one vertices):\n");
+    igraph_diversity(&g, &weights, &result, igraph_vss_all());
+    print_vector(&result);
+
+    igraph_vector_destroy(&weights);
+    igraph_destroy(&g);
+
     /* error conditions are tested from now on */
     VERIFY_FINALLY_STACK();
-    igraph_set_error_handler(igraph_error_handler_ignore);
 
     /* graph with multiple edges */
     igraph_small(&g, 3, IGRAPH_UNDIRECTED, 0,1, 0,2, 2,0, -1);
     igraph_vector_init_int_end(&weights, -1, 3, 2, 8, -1);
-    IGRAPH_ASSERT(igraph_diversity(&g, &weights, &result, igraph_vss_all()) == IGRAPH_EINVAL);
+    CHECK_ERROR(igraph_diversity(&g, &weights, &result, igraph_vss_all()), IGRAPH_EINVAL);
+    igraph_vector_destroy(&weights);
+    igraph_destroy(&g);
+
+    /* negative weights */
+    igraph_small(&g, 3, IGRAPH_UNDIRECTED, 0,1, 0,2, 2,1, -1);
+    igraph_vector_init_int_end(&weights, -1, 3, -2, 8, -1);
+    CHECK_ERROR(igraph_diversity(&g, &weights, &result, igraph_vss_all()), IGRAPH_EINVAL);
     igraph_vector_destroy(&weights);
     igraph_destroy(&g);
 
     /* directed graph */
     igraph_small(&g, 3, IGRAPH_DIRECTED, 0,1, 0,2, -1);
     igraph_vector_init_int_end(&weights, -1, 3, 2, -1);
-    IGRAPH_ASSERT(igraph_diversity(&g, &weights, &result, igraph_vss_all()) == IGRAPH_EINVAL);
+    CHECK_ERROR(igraph_diversity(&g, &weights, &result, igraph_vss_all()), IGRAPH_EINVAL);
     igraph_vector_destroy(&weights);
     igraph_destroy(&g);
 


=====================================
tests/unit/igraph_diversity.out
=====================================
@@ -4,3 +4,5 @@ Empty graph:
 ( NaN NaN NaN NaN NaN )
 Graph with 4 nodes and 5 edges:
 ( 0.970951 0.75 0.69137 1 )
+Tree (having degree-one vertices):
+( 0.918296 0.88686 0.921463 0.934206 0.890492 0 0 0 0 0 )


=====================================
tests/unit/igraph_hrg3.c
=====================================
@@ -68,7 +68,7 @@ int main() {
     igraph_hrg_predict(&karate, &edges, &prob, /* hrg= */ 0, /* start= */ 0,
                        /* num_samples= */ 100, /* num_bins= */ 25);
 
-    /* We do some simple validity tests on the resolts only; the exact results
+    /* We do some simple validity tests on the results only; the exact results
      * are different on i386 vs other platforms due to numerical inaccuracies */
     n = igraph_vector_size(&edges);
     for (i = 0; i < n; i++) {



View it on GitLab: https://salsa.debian.org/med-team/igraph/-/compare/a328bc597740d112269cc7d96e53db7238508176...51607d74f7aeeeb6700eebfb9f9bb5945b03e9e1

-- 
View it on GitLab: https://salsa.debian.org/med-team/igraph/-/compare/a328bc597740d112269cc7d96e53db7238508176...51607d74f7aeeeb6700eebfb9f9bb5945b03e9e1
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/debian-med-commit/attachments/20220409/43763580/attachment-0001.htm>


More information about the debian-med-commit mailing list