Пример #1
0
def test_globals():
    graph = Graph(global_features=torch.rand(3))
    validate_graph(graph)

    graph = Graph(node_features=torch.rand(6, 2),
                  edge_features=torch.rand(5, 2),
                  global_features=torch.rand(3),
                  senders=torch.tensor([0, 0, 1, 1, 2]),
                  receivers=torch.tensor([0, 0, 3, 4, 5]))
    validate_graph(graph)
Пример #2
0
def test_collate_dicts(graphs_nx, features_shapes, device):
    graphs_in = [
        add_random_features(Graph.from_networkx(g),
                            **features_shapes).to(device) for g in graphs_nx
    ]
    graphs_out = list(reversed(graphs_in))
    xs = torch.rand(len(graphs_in), 10, 32)
    ys = torch.rand(len(graphs_in), 7)

    samples = [{
        'in': gi,
        'x': x,
        'y': y,
        'out': go
    } for gi, x, y, go in zip(graphs_in, xs, ys, graphs_out)]
    batch = GraphBatch.collate(samples)

    for g1, g2 in zip(graphs_in, batch['in']):
        assert_graphs_equal(g1, g2)

    torch.testing.assert_allclose(xs, batch['x'])

    torch.testing.assert_allclose(ys, batch['y'])

    for g1, g2 in zip(graphs_out, batch['out']):
        assert_graphs_equal(g1, g2)
Пример #3
0
def test_graph_properties(graph_nx):
    graph_nx = add_dummy_features(graph_nx)
    graph = Graph.from_networkx(graph_nx)

    assert list(graph.degree) == [d for _, d in graph_nx.degree]
    assert list(graph.in_degree) == [d for _, d in graph_nx.in_degree]
    assert list(graph.out_degree) == [d for _, d in graph_nx.out_degree]
Пример #4
0
def test_global_functions(graph_nx):
    graph_nx = add_dummy_features(graph_nx)
    graph = Graph.from_networkx(graph_nx)

    assert graph.global_features.shape == graph.global_features_shape
    assert graph.global_features_as_nodes.shape == (
        graph.num_nodes, *graph.global_features_shape)
    assert graph.global_features_as_edges.shape == (
        graph.num_edges, *graph.global_features_shape)
Пример #5
0
def test_nodes():
    graph = Graph(num_nodes=0)
    validate_graph(graph)
    assert graph.num_nodes == 0

    graph = Graph(num_nodes=10)
    validate_graph(graph)
    assert graph.num_nodes == 10

    graph = Graph(node_features=torch.rand(15, 2))
    validate_graph(graph)
    assert graph.num_nodes == 15
    assert graph.node_features_shape == (2, )

    with pytest.raises(ValueError):
        Graph(num_nodes=-1)

    with pytest.raises(ValueError):
        Graph(num_nodes=0, node_features=torch.rand(15, 2))
Пример #6
0
def test_node_functions(graph_nx):
    graph_nx = add_dummy_features(graph_nx)
    graph = Graph.from_networkx(graph_nx)

    # Features of the outgoing edges
    # By node index
    for node_index in range(graph.num_nodes):
        assert graph.out_edge_features[node_index].shape[
            1:] == graph.edge_features_shape
    # Iterator
    for out_edges in iter(graph.out_edge_features):
        assert out_edges.shape[1:] == graph.edge_features_shape
    # As tensor
    assert graph.out_edge_features(
        aggregation='sum').shape == (graph.num_nodes,
                                     *graph.edge_features_shape)

    # Features of the incoming edges
    # By node index
    for node_index in range(graph.num_nodes):
        assert graph.in_edge_features[node_index].shape[
            1:] == graph.edge_features_shape
    # Iterator
    for in_edges in iter(graph.in_edge_features):
        assert in_edges.shape[1:] == graph.edge_features_shape
    # As tensor
    assert graph.in_edge_features(
        aggregation='sum').shape == (graph.num_nodes,
                                     *graph.edge_features_shape)

    # Features of the successor nodes
    # By node index
    for node_index in range(graph.num_nodes):
        assert graph.successor_features[node_index].shape[
            1:] == graph.node_features_shape
    # Iterator
    for in_edges in iter(graph.successor_features):
        assert in_edges.shape[1:] == graph.node_features_shape
    # As tensor
    assert graph.successor_features(
        aggregation='sum').shape == (graph.num_nodes,
                                     *graph.node_features_shape)

    # Features of the predecessor nodes
    # By node index
    for node_index in range(graph.num_nodes):
        assert graph.predecessor_features[node_index].shape[
            1:] == graph.node_features_shape
    # Iterator
    for in_edges in iter(graph.predecessor_features):
        assert in_edges.shape[1:] == graph.node_features_shape
    # As tensor
    assert graph.predecessor_features(
        aggregation='sum').shape == (graph.num_nodes,
                                     *graph.node_features_shape)
Пример #7
0
def test_empty():
    graph = Graph()
    validate_graph(graph)

    assert graph.num_nodes == 0
    assert graph.node_features is None
    assert graph.node_features_shape is None

    assert graph.num_edges == len(graph.senders) == len(graph.receivers) == 0
    assert graph.edge_features is None
    assert graph.edge_features_shape is None

    assert graph.global_features is None
    assert graph.global_features_shape is None
def test_corner_cases(features_shapes, device):
    # Only some graphs have node/edge features, global features are either present on all of them or absent from all
    gfs = features_shapes['global_features_shape']
    graphs = [
        add_random_features(Graph(num_nodes=0, num_edges=0),
                            global_features_shape=gfs),
        add_random_features(Graph(num_nodes=0, num_edges=0),
                            global_features_shape=gfs),
        add_random_features(Graph(num_nodes=3, num_edges=0),
                            **features_shapes),
        add_random_features(Graph(num_nodes=0, num_edges=0),
                            **features_shapes),
        add_random_features(
            Graph(num_nodes=2,
                  senders=torch.tensor([0, 1]),
                  receivers=torch.tensor([1, 0])), **features_shapes)
    ]
    graphbatch = GraphBatch.from_graphs(graphs).to(device)
    validate_batch(graphbatch)

    for g_orig, g_batch in zip(graphs, graphbatch):
        assert_graphs_equal(g_orig, g_batch.cpu())

    # Global features should be either present on all graphs or absent from all graphs
    with pytest.raises(ValueError):
        GraphBatch.from_graphs([
            Graph(num_nodes=0, num_edges=0),
            add_random_features(Graph(num_nodes=0, num_edges=0),
                                global_features_shape=10)
        ])
    with pytest.raises(ValueError):
        GraphBatch.from_graphs([
            add_random_features(Graph(num_nodes=0, num_edges=0),
                                global_features_shape=10),
            Graph(num_nodes=0, num_edges=0)
        ])
Пример #9
0
def test_collate_tuples(graphs_nx, features_shapes, device):
    graphs_in = [
        add_random_features(Graph.from_networkx(g),
                            **features_shapes).to(device) for g in graphs_nx
    ]
    graphs_out = list(reversed(graphs_in))
    xs = torch.rand(len(graphs_in), 10, 32)
    ys = torch.rand(len(graphs_in), 7)

    samples = list(zip(graphs_in, xs, ys, graphs_out))
    batch = GraphBatch.collate(samples)

    for g1, g2 in zip(graphs_in, batch[0]):
        assert_graphs_equal(g1, g2)

    torch.testing.assert_allclose(xs, batch[1])

    torch.testing.assert_allclose(ys, batch[2])

    for g1, g2 in zip(graphs_out, batch[3]):
        assert_graphs_equal(g1, g2)
Пример #10
0
def test_edge_functions(graph_nx):
    graph_nx = add_dummy_features(graph_nx)
    graph = Graph.from_networkx(graph_nx)

    # Edge features
    # By edge index
    for edge_index in range(graph.num_edges):
        assert graph.edge_features[
            edge_index].shape == graph.edge_features_shape
    # Iterator
    for edge_features in iter(graph.edge_features):
        assert edge_features.shape == graph.edge_features_shape
    # As tensor
    assert graph.edge_features.shape == (graph.num_edges,
                                         *graph.edge_features_shape)

    # Features of the sender nodes
    # By edge index
    for edge_index in range(graph.num_edges):
        assert graph.sender_features[
            edge_index].shape == graph.node_features_shape
    # Iterator
    for edge_features in graph.sender_features:
        assert edge_features.shape == graph.node_features_shape
    # As tensor
    assert graph.sender_features().shape == (graph.num_edges,
                                             *graph.node_features_shape)

    # Features of the receiver nodes
    # By edge index
    for edge_index in range(graph.num_edges):
        assert graph.receiver_features[
            edge_index].shape == graph.node_features_shape
    # Iterator
    for edge_features in graph.receiver_features:
        assert edge_features.shape == graph.node_features_shape
    # As tensor
    assert graph.receiver_features().shape == (graph.num_edges,
                                               *graph.node_features_shape)
Пример #11
0
def test_edges():
    graph = Graph(num_nodes=6,
                  senders=torch.tensor([0, 1, 2, 5, 5]),
                  receivers=torch.tensor([3, 4, 5, 5, 5]))
    validate_graph(graph)
    assert graph.num_edges == len(graph.senders) == len(graph.receivers) == 5

    graph = Graph(num_nodes=6,
                  edge_features=torch.rand(5, 2),
                  senders=torch.tensor([0, 1, 2, 5, 5]),
                  receivers=torch.tensor([3, 4, 5, 5, 5]))
    validate_graph(graph)
    assert graph.num_edges == len(graph.senders) == len(
        graph.receivers) == len(graph.edge_features) == 5
    assert graph.edge_features_shape == (2, )

    # Negative number of edges
    with pytest.raises(ValueError):
        Graph(num_edges=-1)

    # Senders and receivers not given
    with pytest.raises(ValueError):
        Graph(num_edges=3)

    # Senders not given
    with pytest.raises(ValueError):
        Graph(num_edges=3, receivers=torch.arange(10))

    # Receivers not given
    with pytest.raises(ValueError):
        Graph(num_edges=3, senders=torch.arange(10))

    # Senders and receivers given, but not matching number of edges
    with pytest.raises(ValueError):
        Graph(num_edges=3,
              senders=torch.arange(10),
              receivers=torch.arange(10))

    # Edges on a graph with no nodes
    with pytest.raises(ValueError):
        Graph(senders=torch.tensor([0, 1, 2]),
              receivers=torch.tensor([3, 4, 5]))

    # Different number of senders and receivers
    with pytest.raises(ValueError):
        Graph(num_nodes=6,
              senders=torch.tensor([0]),
              receivers=torch.tensor([3, 4, 5]))

    # Indexes out-of-bounds
    with pytest.raises(ValueError):
        Graph(num_nodes=6,
              senders=torch.tensor([0, 1, 1000]),
              receivers=torch.tensor([3, 4, 5]))

    # Indexes out-of-bounds
    with pytest.raises(ValueError):
        Graph(num_nodes=6,
              senders=torch.tensor([0, 1, 2]),
              receivers=torch.tensor([3, 4, 1000]))

    # Indexes out-of-bounds
    with pytest.raises(ValueError):
        Graph(num_nodes=6,
              senders=torch.tensor([-1000, 1, 2]),
              receivers=torch.tensor([3, 4, 5]))

    # Indexes out-of-bounds
    with pytest.raises(ValueError):
        Graph(num_nodes=6,
              senders=torch.tensor([0, 1, 2]),
              receivers=torch.tensor([-1000, 4, 5]))

    # Senders, receivers and number of edges given, but not matching features
    with pytest.raises(ValueError):
        Graph(num_nodes=6,
              senders=torch.tensor([0, 1]),
              receivers=torch.tensor([3, 4]),
              edge_features=torch.rand(9, 2))
Пример #12
0
def test_from_networkx(graph_nx, features_shapes):
    graph_nx = add_random_features(graph_nx, **features_shapes)
    graph = Graph.from_networkx(graph_nx)
    assert_graphs_equal(graph_nx, graph)
Пример #13
0
def graphs() -> Sequence[Graph]:
    return [Graph.from_networkx(g) for g in graphs_for_test().values()]
Пример #14
0
def graph(request) -> Graph:
    return Graph.from_networkx(request.param)