示例#1
0
def test_gnp_augmentation():
    rng = random.Random(0)
    G = nx.gnp_random_graph(30, 0.005, seed=0)
    # Randomly make edges available
    avail = {(u, v): 1 + rng.random()
             for u, v in complement_edges(G) if rng.random() < .25}
    _check_augmentations(G, avail)
def test_gnp_augmentation():
    rng = random.Random(0)
    G = nx.gnp_random_graph(30, 0.005, seed=0)
    # Randomly make edges available
    avail = {(u, v): 1 + rng.random()
             for u, v in complement_edges(G)
             if rng.random() < .25}
    _check_augmentations(G, avail)
示例#3
0
def test_weight_key():
    G = nx.Graph()
    G.add_nodes_from([1, 2, 3, 4, 5, 6, 7, 8, 9])
    G.add_edges_from([(3, 8), (1, 2), (2, 3)])
    impossible = {(3, 6), (3, 9)}
    rng = random.Random(0)
    avail_uv = list(set(complement_edges(G)) - impossible)
    avail = [(u, v, {'cost': rng.random()}) for u, v in avail_uv]

    _augment_and_check(G, k=1)
    _augment_and_check(G, k=1, avail=avail_uv)
    _augment_and_check(G, k=1, avail=avail, weight='cost')

    _check_augmentations(G, avail, weight='cost')
def test_weight_key():
    G = nx.Graph()
    G.add_nodes_from([
        1, 2, 3, 4, 5, 6, 7, 8, 9])
    G.add_edges_from([(3, 8), (1, 2), (2, 3)])
    impossible = {(3, 6), (3, 9)}
    rng = random.Random(0)
    avail_uv = list(set(complement_edges(G)) - impossible)
    avail = [(u, v, {'cost': rng.random()}) for u, v in avail_uv]

    _augment_and_check(G, k=1)
    _augment_and_check(G, k=1, avail=avail_uv)
    _augment_and_check(G, k=1, avail=avail, weight='cost')

    _check_augmentations(G, avail, weight='cost')
示例#5
0
def _check_augmentations(G,
                         avail=None,
                         max_k=None,
                         weight=None,
                         verbose=False):
    """ Helper to check weighted/unweighted cases with multiple values of k """
    # Using all available edges, find the maximum edge-connectivity
    try:
        orig_k = nx.edge_connectivity(G)
    except nx.NetworkXPointlessConcept:
        orig_k = 0

    if avail is not None:
        all_aug_edges = _unpack_available_edges(avail, weight=weight)[0]
        G_aug_all = G.copy()
        G_aug_all.add_edges_from(all_aug_edges)
        try:
            max_aug_k = nx.edge_connectivity(G_aug_all)
        except nx.NetworkXPointlessConcept:
            max_aug_k = 0
    else:
        max_aug_k = G.number_of_nodes() - 1

    if max_k is None:
        max_k = min(4, max_aug_k)

    avail_uniform = {e: 1 for e in complement_edges(G)}

    if verbose:
        print('\n=== CHECK_AUGMENTATION ===')
        print('G.number_of_nodes = {!r}'.format(G.number_of_nodes()))
        print('G.number_of_edges = {!r}'.format(G.number_of_edges()))
        print('max_k = {!r}'.format(max_k))
        print('max_aug_k = {!r}'.format(max_aug_k))
        print('orig_k = {!r}'.format(orig_k))

    # check augmentation for multiple values of k
    for k in range(1, max_k + 1):
        if verbose:
            print('---------------')
            print('Checking k = {}'.format(k))

        # Check the unweighted version
        if verbose:
            print('unweighted case')
        aug_edges1, info1 = _augment_and_check(G,
                                               k=k,
                                               verbose=verbose,
                                               orig_k=orig_k)

        # Check that the weighted version with all available edges and uniform
        # weights gives a similar solution to the unweighted case.
        if verbose:
            print('weighted uniform case')
        aug_edges2, info2 = _augment_and_check(G,
                                               k=k,
                                               avail=avail_uniform,
                                               verbose=verbose,
                                               orig_k=orig_k,
                                               max_aug_k=G.number_of_nodes() -
                                               1)

        # Check the weighted version
        if avail is not None:
            if verbose:
                print('weighted case')
            aug_edges3, info3 = _augment_and_check(G,
                                                   k=k,
                                                   avail=avail,
                                                   weight=weight,
                                                   verbose=verbose,
                                                   max_aug_k=max_aug_k,
                                                   orig_k=orig_k)

        if aug_edges1 is not None:
            # Check approximation ratios
            if k == 1:
                # when k=1, both solutions should be optimal
                assert_equal(info2['total_weight'], info1['total_weight'])
            if k == 2:
                # when k=2, the weighted version is an approximation
                if orig_k == 0:
                    # the approximation ratio is 3 if G is not connected
                    assert_less_equal(info2['total_weight'],
                                      info1['total_weight'] * 3)
                else:
                    # the approximation ratio is 2 if G is was connected
                    assert_less_equal(info2['total_weight'],
                                      info1['total_weight'] * 2)
                _check_unconstrained_bridge_property(G, info1)
示例#6
0
def _augment_and_check(G,
                       k,
                       avail=None,
                       weight=None,
                       verbose=False,
                       orig_k=None,
                       max_aug_k=None):
    """
    Does one specific augmentation and checks for properties of the result
    """
    if orig_k is None:
        try:
            orig_k = nx.edge_connectivity(G)
        except nx.NetworkXPointlessConcept:
            orig_k = 0
    info = {}
    try:
        if avail is not None:
            # ensure avail is in dict form
            avail_dict = dict(
                zip(*_unpack_available_edges(avail, weight=weight)))
        else:
            avail_dict = None
        try:
            # Find the augmentation if possible
            generator = nx.k_edge_augmentation(G,
                                               k=k,
                                               weight=weight,
                                               avail=avail)
            assert_false(isinstance(generator, list),
                         'should always return an iter')
            aug_edges = []
            for edge in generator:
                aug_edges.append(edge)
        except nx.NetworkXUnfeasible:
            infeasible = True
            info['infeasible'] = True
            assert_equal(len(aug_edges), 0,
                         'should not generate anything if unfeasible')

            if avail is None:
                n_nodes = G.number_of_nodes()
                assert_less_equal(
                    n_nodes, k,
                    ('unconstrained cases are only unfeasible if |V| <= k. '
                     'Got |V|={} and k={}'.format(n_nodes, k)))
            else:
                if max_aug_k is None:
                    G_aug_all = G.copy()
                    G_aug_all.add_edges_from(avail_dict.keys())
                    try:
                        max_aug_k = nx.edge_connectivity(G_aug_all)
                    except nx.NetworkXPointlessConcept:
                        max_aug_k = 0

                assert_less(
                    max_aug_k, k,
                    ('avail should only be unfeasible if using all edges '
                     'does not achieve k-edge-connectivity'))

            # Test for a partial solution
            partial_edges = list(
                nx.k_edge_augmentation(G,
                                       k=k,
                                       weight=weight,
                                       partial=True,
                                       avail=avail))

            info['n_partial_edges'] = len(partial_edges)

            if avail_dict is None:
                assert_equal(
                    set(partial_edges), set(complement_edges(G)),
                    ('unweighted partial solutions should be the complement'))
            elif len(avail_dict) > 0:
                H = G.copy()

                # Find the partial / full augmented connectivity
                H.add_edges_from(partial_edges)
                partial_conn = nx.edge_connectivity(H)

                H.add_edges_from(set(avail_dict.keys()))
                full_conn = nx.edge_connectivity(H)

                # Full connectivity should be no better than our partial
                # solution.
                assert_equal(partial_conn, full_conn,
                             'adding more edges should not increase k-conn')

            # Find the new edge-connectivity after adding the augmenting edges
            aug_edges = partial_edges
        else:
            infeasible = False

        # Find the weight of the augmentation
        num_edges = len(aug_edges)
        if avail is not None:
            total_weight = sum([avail_dict[e] for e in aug_edges])
        else:
            total_weight = num_edges

        info['total_weight'] = total_weight
        info['num_edges'] = num_edges

        # Find the new edge-connectivity after adding the augmenting edges
        G_aug = G.copy()
        G_aug.add_edges_from(aug_edges)
        try:
            aug_k = nx.edge_connectivity(G_aug)
        except nx.NetworkXPointlessConcept:
            aug_k = 0
        info['aug_k'] = aug_k

        # Do checks
        if not infeasible and orig_k < k:
            assert_greater_equal(
                info['aug_k'], k,
                ('connectivity should increase to k={} or more'.format(k)))

        assert_greater_equal(info['aug_k'], orig_k,
                             ('augmenting should never reduce connectivity'))

        _assert_solution_properties(G, aug_edges, avail_dict)

    except Exception:
        info['failed'] = True
        print('edges = {}'.format(list(G.edges())))
        print('nodes = {}'.format(list(G.nodes())))
        print('aug_edges = {}'.format(list(aug_edges)))
        print('info  = {}'.format(info))
        raise
    else:
        if verbose:
            print('info  = {}'.format(info))

    if infeasible:
        aug_edges = None
    return aug_edges, info
示例#7
0
def complement_edges(G):
    from networkx.algorithms.connectivity.edge_augmentation import complement_edges
    return it.starmap(e_, complement_edges(G))
def _augment_and_check(G,
                       k,
                       avail=None,
                       weight=None,
                       verbose=False,
                       orig_k=None,
                       max_aug_k=None):
    """
    Does one specific augmentation and checks for properties of the result
    """
    if orig_k is None:
        try:
            orig_k = nx.edge_connectivity(G)
        except nx.NetworkXPointlessConcept:
            orig_k = 0
    info = {}
    try:
        if avail is not None:
            # ensure avail is in dict form
            avail_dict = dict(
                zip(*_unpack_available_edges(avail, weight=weight)))
        else:
            avail_dict = None
        try:
            # Find the augmentation if possible
            generator = nx.k_edge_augmentation(G,
                                               k=k,
                                               weight=weight,
                                               avail=avail)
            assert not isinstance(generator,
                                  list), "should always return an iter"
            aug_edges = []
            for edge in generator:
                aug_edges.append(edge)
        except nx.NetworkXUnfeasible:
            infeasible = True
            info["infeasible"] = True
            assert len(
                aug_edges) == 0, "should not generate anything if unfeasible"

            if avail is None:
                n_nodes = G.number_of_nodes()
                assert n_nodes <= k, (
                    "unconstrained cases are only unfeasible if |V| <= k. "
                    f"Got |V|={n_nodes} and k={k}")
            else:
                if max_aug_k is None:
                    G_aug_all = G.copy()
                    G_aug_all.add_edges_from(avail_dict.keys())
                    try:
                        max_aug_k = nx.edge_connectivity(G_aug_all)
                    except nx.NetworkXPointlessConcept:
                        max_aug_k = 0

                assert max_aug_k < k, (
                    "avail should only be unfeasible if using all edges "
                    "does not achieve k-edge-connectivity")

            # Test for a partial solution
            partial_edges = list(
                nx.k_edge_augmentation(G,
                                       k=k,
                                       weight=weight,
                                       partial=True,
                                       avail=avail))

            info["n_partial_edges"] = len(partial_edges)

            if avail_dict is None:
                assert set(partial_edges) == set(
                    complement_edges(G)
                ), "unweighted partial solutions should be the complement"
            elif len(avail_dict) > 0:
                H = G.copy()

                # Find the partial / full augmented connectivity
                H.add_edges_from(partial_edges)
                partial_conn = nx.edge_connectivity(H)

                H.add_edges_from(set(avail_dict.keys()))
                full_conn = nx.edge_connectivity(H)

                # Full connectivity should be no better than our partial
                # solution.
                assert (partial_conn == full_conn
                        ), "adding more edges should not increase k-conn"

            # Find the new edge-connectivity after adding the augmenting edges
            aug_edges = partial_edges
        else:
            infeasible = False

        # Find the weight of the augmentation
        num_edges = len(aug_edges)
        if avail is not None:
            total_weight = sum([avail_dict[e] for e in aug_edges])
        else:
            total_weight = num_edges

        info["total_weight"] = total_weight
        info["num_edges"] = num_edges

        # Find the new edge-connectivity after adding the augmenting edges
        G_aug = G.copy()
        G_aug.add_edges_from(aug_edges)
        try:
            aug_k = nx.edge_connectivity(G_aug)
        except nx.NetworkXPointlessConcept:
            aug_k = 0
        info["aug_k"] = aug_k

        # Do checks
        if not infeasible and orig_k < k:
            assert info[
                "aug_k"] >= k, f"connectivity should increase to k={k} or more"

        assert info[
            "aug_k"] >= orig_k, "augmenting should never reduce connectivity"

        _assert_solution_properties(G, aug_edges, avail_dict)

    except Exception:
        info["failed"] = True
        print(f"edges = {list(G.edges())}")
        print(f"nodes = {list(G.nodes())}")
        print(f"aug_edges = {list(aug_edges)}")
        print(f"info  = {info}")
        raise
    else:
        if verbose:
            print(f"info  = {info}")

    if infeasible:
        aug_edges = None
    return aug_edges, info
def _check_augmentations(G, avail=None, max_k=None, weight=None,
                         verbose=False):
    """ Helper to check weighted/unweighted cases with multiple values of k """
    # Using all available edges, find the maximum edge-connectivity
    try:
        orig_k = nx.edge_connectivity(G)
    except nx.NetworkXPointlessConcept:
        orig_k = 0

    if avail is not None:
        all_aug_edges = _unpack_available_edges(avail, weight=weight)[0]
        G_aug_all = G.copy()
        G_aug_all.add_edges_from(all_aug_edges)
        try:
            max_aug_k = nx.edge_connectivity(G_aug_all)
        except nx.NetworkXPointlessConcept:
            max_aug_k = 0
    else:
        max_aug_k = G.number_of_nodes() - 1

    if max_k is None:
        max_k = min(4, max_aug_k)

    avail_uniform = {e: 1 for e in complement_edges(G)}

    if verbose:
        print('\n=== CHECK_AUGMENTATION ===')
        print('G.number_of_nodes = {!r}'.format(G.number_of_nodes()))
        print('G.number_of_edges = {!r}'.format(G.number_of_edges()))
        print('max_k = {!r}'.format(max_k))
        print('max_aug_k = {!r}'.format(max_aug_k))
        print('orig_k = {!r}'.format(orig_k))

    # check augmentation for multiple values of k
    for k in range(1, max_k + 1):
        if verbose:
            print('---------------')
            print('Checking k = {}'.format(k))

        # Check the unweighted version
        if verbose:
            print('unweighted case')
        aug_edges1, info1 = _augment_and_check(
            G, k=k,  verbose=verbose, orig_k=orig_k)

        # Check that the weighted version with all available edges and uniform
        # weights gives a similar solution to the unweighted case.
        if verbose:
            print('weighted uniform case')
        aug_edges2, info2 = _augment_and_check(
            G, k=k, avail=avail_uniform, verbose=verbose,
            orig_k=orig_k,
            max_aug_k=G.number_of_nodes() - 1)

        # Check the weighted version
        if avail is not None:
            if verbose:
                print('weighted case')
            aug_edges3, info3 = _augment_and_check(
                G, k=k, avail=avail, weight=weight, verbose=verbose,
                max_aug_k=max_aug_k, orig_k=orig_k)

        if aug_edges1 is not None:
            # Check approximation ratios
            if k == 1:
                # when k=1, both solutions should be optimal
                assert_equal(info2['total_weight'], info1['total_weight'])
            if k == 2:
                # when k=2, the weighted version is an approximation
                if orig_k == 0:
                    # the approximation ratio is 3 if G is not connected
                    assert_less_equal(info2['total_weight'],
                                      info1['total_weight'] * 3)
                else:
                    # the approximation ratio is 2 if G is was connected
                    assert_less_equal(info2['total_weight'],
                                      info1['total_weight'] * 2)
                _check_unconstrained_bridge_property(G, info1)
示例#10
0
def _augment_and_check(G, k, avail=None, weight=None, verbose=False,
                       orig_k=None, max_aug_k=None):
    """
    Does one specific augmentation and checks for properties of the result
    """
    if orig_k is None:
        try:
            orig_k = nx.edge_connectivity(G)
        except nx.NetworkXPointlessConcept:
            orig_k = 0
    info = {}
    try:
        if avail is not None:
            # ensure avail is in dict form
            avail_dict = dict(zip(*_unpack_available_edges(avail,
                                                           weight=weight)))
        else:
            avail_dict = None
        try:
            # Find the augmentation if possible
            generator = nx.k_edge_augmentation(G, k=k, weight=weight,
                                               avail=avail)
            assert_false(isinstance(generator, list),
                         'should always return an iter')
            aug_edges = []
            for edge in generator:
                aug_edges.append(edge)
        except nx.NetworkXUnfeasible:
            infeasible = True
            info['infeasible'] = True
            assert_equal(len(aug_edges), 0,
                         'should not generate anything if unfeasible')

            if avail is None:
                n_nodes = G.number_of_nodes()
                assert_less_equal(n_nodes, k, (
                    'unconstrained cases are only unfeasible if |V| <= k. '
                    'Got |V|={} and k={}'.format(n_nodes, k)
                ))
            else:
                if max_aug_k is None:
                    G_aug_all = G.copy()
                    G_aug_all.add_edges_from(avail_dict.keys())
                    try:
                        max_aug_k = nx.edge_connectivity(G_aug_all)
                    except nx.NetworkXPointlessConcept:
                        max_aug_k = 0

                assert_less(max_aug_k, k, (
                    'avail should only be unfeasible if using all edges '
                    'doesnt acheive k-edge-connectivity'))

            # Test for a partial solution
            partial_edges = list(nx.k_edge_augmentation(
                G, k=k, weight=weight, partial=True, avail=avail))

            info['n_partial_edges'] = len(partial_edges)

            if avail_dict is None:
                assert_equal(set(partial_edges), set(complement_edges(G)), (
                    'unweighted partial solutions should be the complement'))
            elif len(avail_dict) > 0:
                H = G.copy()

                # Find the partial / full augmented connectivity
                H.add_edges_from(partial_edges)
                partial_conn = nx.edge_connectivity(H)

                H.add_edges_from(set(avail_dict.keys()))
                full_conn = nx.edge_connectivity(H)

                # Full connectivity should be no better than our partial
                # solution.
                assert_equal(partial_conn, full_conn,
                             'adding more edges should not increase k-conn')

            # Find the new edge-connectivity after adding the augmenting edges
            aug_edges = partial_edges
        else:
            infeasible = False

        # Find the weight of the augmentation
        num_edges = len(aug_edges)
        if avail is not None:
            total_weight = sum([avail_dict[e] for e in aug_edges])
        else:
            total_weight = num_edges

        info['total_weight'] = total_weight
        info['num_edges'] = num_edges

        # Find the new edge-connectivity after adding the augmenting edges
        G_aug = G.copy()
        G_aug.add_edges_from(aug_edges)
        try:
            aug_k = nx.edge_connectivity(G_aug)
        except nx.NetworkXPointlessConcept:
            aug_k = 0
        info['aug_k'] = aug_k

        # Do checks
        if not infeasible and orig_k < k:
            assert_greater_equal(info['aug_k'], k, (
                'connectivity should increase to k={} or more'.format(k)))

        assert_greater_equal(info['aug_k'], orig_k, (
            'augmenting should never reduce connectivity'))

        _assert_solution_properties(G, aug_edges, avail_dict)

    except Exception:
        info['failed'] = True
        print('edges = {}'.format(list(G.edges())))
        print('nodes = {}'.format(list(G.nodes())))
        print('aug_edges = {}'.format(list(aug_edges)))
        print('info  = {}'.format(info))
        raise
    else:
        if verbose:
            print('info  = {}'.format(info))

    if infeasible:
        aug_edges = None
    return aug_edges, info