Repository: graspologic-org/graspologic

Issue:
[BUG] Possible bug in _approximate_prune in auto layout
I've got an email from someone and it seems like `_approximate_prune` is failing.  I don't have a ton of details around this yet but it needs to be investigated!



Discussion:
Adding the following to `tests/layouts/test_auto.py`

```python
    def test_exercise_approximate_prune(self):
        form = nx.erdos_renyi_graph(100, 0.7, directed=False)
        graph = nx.Graph()
        rng = random.Random(12345)
        for source, target in form.edges():
            graph.add_edge(str(source), str(target), weight=rng.uniform(0.0, 10.0))

        result_graph, positions = layout_umap(
            graph,
            max_edges=100
        )
```

Results in the following traceback and error:

```python
graspologic/layouts/auto.py:202: in layout_umap
    lcc_graph, tensors, labels = _node2vec_for_layout(graph, max_edges, random_seed)
graspologic/layouts/auto.py:244: in _node2vec_for_layout
    graph = _approximate_prune(graph, max_edges)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

graph = <networkx.classes.graph.Graph object at 0x12ce62430>, max_edges_to_keep = 100

    def _approximate_prune(graph: nx.Graph, max_edges_to_keep: int = 1000000) -> nx.Graph:
        num_edges = len(graph.edges())
        logger.info(f"num edges: {num_edges}")

        if num_edges > max_edges_to_keep:
            histogram, bins = histogram_edge_weight(graph, bin_directive=100)
            counts = 0
            bin_edge_for_maximum_weight = bins[0]
            for i, count in reversed(list(enumerate(histogram))):
                counts += count
                if counts >= max_edges_to_keep:
                    bin_edge_for_maximum_weight = bins[i + 1]
                    break
>           threshold = bins[bin_edge_for_maximum_weight]
E           IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices

graspologic/layouts/auto.py:230: IndexError
```


        

Resolving patch:
diff --git a/graspologic/layouts/auto.py b/graspologic/layouts/auto.py
--- a/graspologic/layouts/auto.py
+++ b/graspologic/layouts/auto.py
@@ -227,7 +227,7 @@ def _approximate_prune(graph: nx.Graph, max_edges_to_keep: int = 1000000) -> nx.
             if counts >= max_edges_to_keep:
                 bin_edge_for_maximum_weight = bins[i + 1]
                 break
-        threshold = bins[bin_edge_for_maximum_weight]
+        threshold = bin_edge_for_maximum_weight
         graph = cut_edges_by_weight(
             graph, cut_threshold=threshold, cut_process="smaller_than_inclusive"
         )


Test patch:
diff --git a/tests/layouts/test_auto.py b/tests/layouts/test_auto.py
--- a/tests/layouts/test_auto.py
+++ b/tests/layouts/test_auto.py
@@ -1,6 +1,7 @@
 # Copyright (c) Microsoft Corporation and contributors.
 # Licensed under the MIT License.
 
+import random
 import unittest
 
 import networkx as nx
@@ -63,6 +64,16 @@ def test_layout_umap_directed_unweighted(self):
 
         self.assertEqual(len(node_positions), len(graph.nodes()))
 
+    def test_exercise_approximate_prune(self):
+        form = nx.erdos_renyi_graph(100, 0.7, directed=False)
+        graph = nx.Graph()
+        rng = random.Random(12345)
+        for source, target in form.edges():
+            graph.add_edge(str(source), str(target), weight=rng.uniform(0.0, 10.0))
+
+        result_graph, positions = layout_umap(graph, max_edges=100)
+        self.assertTrue(result_graph.number_of_edges() <= 100)
+
 
 if __name__ == "__main__":
     unittest.main()