142 lines
4.0 KiB
Python
142 lines
4.0 KiB
Python
|
# Copyright (C) 2018
|
||
|
# Robert Gmyr <robert@gmyr.net>
|
||
|
# All rights reserved.
|
||
|
# BSD license.
|
||
|
"""Unit tests for the sparsifier computation functions."""
|
||
|
import pytest
|
||
|
import networkx as nx
|
||
|
from networkx.utils import py_random_state
|
||
|
|
||
|
|
||
|
_seed = 2
|
||
|
|
||
|
|
||
|
def _test_spanner(G, spanner, stretch, weight=None):
|
||
|
"""Test whether a spanner is valid.
|
||
|
|
||
|
This function tests whether the given spanner is a subgraph of the
|
||
|
given graph G with the same node set. It also tests for all shortest
|
||
|
paths whether they adhere to the given stretch.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
G : NetworkX graph
|
||
|
The original graph for which the spanner was constructed.
|
||
|
|
||
|
spanner : NetworkX graph
|
||
|
The spanner to be tested.
|
||
|
|
||
|
stretch : float
|
||
|
The proclaimed stretch of the spanner.
|
||
|
|
||
|
weight : object
|
||
|
The edge attribute to use as distance.
|
||
|
"""
|
||
|
# check node set
|
||
|
assert set(G.nodes()) == set(spanner.nodes())
|
||
|
|
||
|
# check edge set and weights
|
||
|
for u, v in spanner.edges():
|
||
|
assert G.has_edge(u, v)
|
||
|
if weight:
|
||
|
assert spanner[u][v][weight] == G[u][v][weight]
|
||
|
|
||
|
# check connectivity and stretch
|
||
|
original_length = dict(nx.shortest_path_length(G, weight=weight))
|
||
|
spanner_length = dict(nx.shortest_path_length(spanner, weight=weight))
|
||
|
for u in G.nodes():
|
||
|
for v in G.nodes():
|
||
|
if u in original_length and v in original_length[u]:
|
||
|
assert spanner_length[u][v] <= stretch * original_length[u][v]
|
||
|
|
||
|
|
||
|
@py_random_state(1)
|
||
|
def _assign_random_weights(G, seed=None):
|
||
|
"""Assigns random weights to the edges of a graph.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
|
||
|
G : NetworkX graph
|
||
|
The original graph for which the spanner was constructed.
|
||
|
|
||
|
seed : integer, random_state, or None (default)
|
||
|
Indicator of random number generation state.
|
||
|
See :ref:`Randomness<randomness>`.
|
||
|
"""
|
||
|
for u, v in G.edges():
|
||
|
G[u][v]['weight'] = seed.random()
|
||
|
|
||
|
|
||
|
def test_spanner_trivial():
|
||
|
"""Test a trivial spanner with stretch 1."""
|
||
|
G = nx.complete_graph(20)
|
||
|
spanner = nx.spanner(G, 1, seed=_seed)
|
||
|
|
||
|
for u, v in G.edges:
|
||
|
assert(spanner.has_edge(u, v))
|
||
|
|
||
|
|
||
|
def test_spanner_unweighted_complete_graph():
|
||
|
"""Test spanner construction on a complete unweighted graph."""
|
||
|
G = nx.complete_graph(20)
|
||
|
|
||
|
spanner = nx.spanner(G, 4, seed=_seed)
|
||
|
_test_spanner(G, spanner, 4)
|
||
|
|
||
|
spanner = nx.spanner(G, 10, seed=_seed)
|
||
|
_test_spanner(G, spanner, 10)
|
||
|
|
||
|
|
||
|
def test_spanner_weighted_complete_graph():
|
||
|
"""Test spanner construction on a complete weighted graph."""
|
||
|
G = nx.complete_graph(20)
|
||
|
_assign_random_weights(G, seed=_seed)
|
||
|
|
||
|
spanner = nx.spanner(G, 4, weight='weight', seed=_seed)
|
||
|
_test_spanner(G, spanner, 4, weight='weight')
|
||
|
|
||
|
spanner = nx.spanner(G, 10, weight='weight', seed=_seed)
|
||
|
_test_spanner(G, spanner, 10, weight='weight')
|
||
|
|
||
|
|
||
|
def test_spanner_unweighted_gnp_graph():
|
||
|
"""Test spanner construction on an unweighted gnp graph."""
|
||
|
G = nx.gnp_random_graph(20, 0.4, seed=_seed)
|
||
|
|
||
|
spanner = nx.spanner(G, 4, seed=_seed)
|
||
|
_test_spanner(G, spanner, 4)
|
||
|
|
||
|
spanner = nx.spanner(G, 10, seed=_seed)
|
||
|
_test_spanner(G, spanner, 10)
|
||
|
|
||
|
|
||
|
def test_spanner_weighted_gnp_graph():
|
||
|
"""Test spanner construction on an weighted gnp graph."""
|
||
|
G = nx.gnp_random_graph(20, 0.4, seed=_seed)
|
||
|
_assign_random_weights(G, seed=_seed)
|
||
|
|
||
|
spanner = nx.spanner(G, 4, weight='weight', seed=_seed)
|
||
|
_test_spanner(G, spanner, 4, weight='weight')
|
||
|
|
||
|
spanner = nx.spanner(G, 10, weight='weight', seed=_seed)
|
||
|
_test_spanner(G, spanner, 10, weight='weight')
|
||
|
|
||
|
|
||
|
def test_spanner_unweighted_disconnected_graph():
|
||
|
"""Test spanner construction on a disconnected graph."""
|
||
|
G = nx.disjoint_union(nx.complete_graph(10), nx.complete_graph(10))
|
||
|
|
||
|
spanner = nx.spanner(G, 4, seed=_seed)
|
||
|
_test_spanner(G, spanner, 4)
|
||
|
|
||
|
spanner = nx.spanner(G, 10, seed=_seed)
|
||
|
_test_spanner(G, spanner, 10)
|
||
|
|
||
|
|
||
|
def test_spanner_invalid_stretch():
|
||
|
"""Check whether an invalid stretch is caught."""
|
||
|
with pytest.raises(ValueError):
|
||
|
G = nx.empty_graph()
|
||
|
nx.spanner(G, 0)
|