-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5 from PatrickOHara/pctsp-37-sparse
Remove edges from TSPLIB to make sparse graphs
- Loading branch information
Showing
6 changed files
with
172 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -427,6 +427,7 @@ good-names=i, | |
v, | ||
w, | ||
G, | ||
H, | ||
T, | ||
x, | ||
y, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
"""Tests for sparsity""" | ||
|
||
import networkx as nx | ||
from tsplib95.models import StandardProblem | ||
from tspwplib.complete import is_complete_with_self_loops | ||
from tspwplib.sparsity import remove_random_edges_from_graph | ||
from tspwplib.utils import build_path_to_tsplib_instance | ||
|
||
|
||
def test_remove_random_edges_from_graph( | ||
tsplib_root, instance_name, edge_removal_probability | ||
): | ||
"""Test the right number of edges are removed""" | ||
filepath = build_path_to_tsplib_instance(tsplib_root, instance_name) | ||
problem = StandardProblem.load(filepath) | ||
complete_graph = problem.get_graph() | ||
assert is_complete_with_self_loops(complete_graph) | ||
smaller_graph = remove_random_edges_from_graph( | ||
complete_graph, edge_removal_probability=edge_removal_probability | ||
) | ||
# edge cases | ||
if edge_removal_probability == 0: | ||
assert smaller_graph.number_of_edges() == complete_graph.number_of_edges() | ||
elif edge_removal_probability == 1.0: | ||
assert smaller_graph.number_of_edges() == 0 | ||
# sufficient number of nodes for randomness to not have big effect | ||
elif smaller_graph.number_of_nodes() > 10: | ||
assert not is_complete_with_self_loops(smaller_graph) | ||
num_edges_lower_bound = complete_graph.number_of_edges() * ( | ||
1 - edge_removal_probability - 0.1 | ||
) | ||
num_edges_upper_bound = complete_graph.number_of_edges() * ( | ||
1 - edge_removal_probability + 0.1 | ||
) | ||
assert ( | ||
num_edges_lower_bound | ||
<= smaller_graph.number_of_edges() | ||
<= num_edges_upper_bound | ||
) | ||
assert nx.is_connected(smaller_graph) | ||
|
||
|
||
def test_measure_sparsity_metrics(): | ||
"""Test the sparsity of graphs is measured correctly""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
"""Functions for complete graphs""" | ||
|
||
import networkx as nx | ||
|
||
|
||
def is_complete(G: nx.Graph) -> bool: | ||
"""Check if the graph is complete | ||
Args: | ||
G: Simple graph | ||
Returns: | ||
True if the graph is complete, false otherwise | ||
Note: | ||
Assumes no self loops | ||
""" | ||
for u in G: | ||
for v in G: | ||
if not G.has_edge(u, v) and u != v: | ||
return False | ||
return True | ||
|
||
|
||
def is_complete_with_self_loops(G: nx.Graph) -> bool: | ||
"""Check if the graph is complete, and every vertex has a self loop | ||
Args: | ||
G: Simple graph | ||
Returns: | ||
True if the graph is complete, false otherwise | ||
""" | ||
for u in G: | ||
if not G.has_edge(u, u): | ||
return False | ||
return is_complete(G) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
"""Functions for creating and measuring the sparsity of graphs. | ||
To calculate the k-degeneracy of a graph you can use networkx: | ||
```python | ||
degeneracy(G) = max(networkx.core_number(G).values()) | ||
``` | ||
""" | ||
|
||
import random | ||
from typing import Dict | ||
import networkx as nx | ||
|
||
|
||
def remove_random_edges_from_graph( | ||
G: nx.Graph, edge_removal_probability: float = 0.5 | ||
) -> nx.Graph: | ||
"""Remove edges from the graph to make it more sparse. | ||
Edges are removed randomly with uniform and indepedent probability. | ||
Args: | ||
G: Complete graph | ||
edge_removal_probability: Probability of removing an edge from G | ||
Returns: | ||
New graph with edge removed | ||
""" | ||
# make copy of graph to avoid editing original copy | ||
H = G.copy() | ||
|
||
# for each edge in G, remove in H if random number if less than edge removal prob | ||
for u, v in G.edges(): | ||
if random.random() < edge_removal_probability: | ||
H.remove_edge(u, v) | ||
return H | ||
|
||
|
||
def measure_sparsity_metrics(G: nx.Graph) -> Dict[str, float]: | ||
"""Calculate metrics for how sparse a graph is""" | ||
return dict( | ||
degeneracy=max(nx.core_number(G).values()), | ||
degree_ratio=sum(nx.degree(G).values()) / (2 * G.number_of_edges()), | ||
) |