Cannot assign edge data after `g.remove_edges`

I am using the GCN model on “Cora” dataset. I am performing some edge deletion and addition before fitting the GCN model and it throws the error below:

File “/home/uday/Robust_Graph_github/RobustGraph/”, line 131, in forward
h = layer(g,h)
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/torch/nn/modules/”, line 547, in call
result = self.forward(*input, **kwargs)
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/nn/pytorch/conv/”, line 118, in forward
graph.ndata[‘h’] = feat
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/”, line 65, in setitem
self._graph.set_n_repr({key : val}, self._nodes)
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/”, line 1794, in set_n_repr
self._node_frame[key] = val
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/”, line 671, in setitem
self.update_data(key, val, inplace=False)
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/”, line 698, in update_data
self.update_column(key, val, inplace=inplace)
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/”, line 729, in update_column
self._frame[name] = data
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/”, line 328, in setitem
self.update_column(name, data)
File “/home/uday/anaconda3/envs/py36/lib/python3.6/site-packages/dgl/”, line 415, in update_column
(self.num_rows, len(col)))
dgl._ffi.base.DGLError: Expected data to have 0 rows, got 2708.

Hi, could you please elaborate more about the input g, h by

print(g, h.shape)

before calling h=layer(g, h)?

Thank you for the reply!

DGLGraph(num_nodes=2708, num_edges=13232,
edata_schemes={}) torch.Size([2708, 1433])

I am using the following function to create structural perturbations in the graph like adding new edges and deleting existing ones.

    def DICE(self, g, labels, ptb_ratio):
        """DICE (disconnect internally, connect externally) is a heuristic structure perturbation
    where, for each perturbation, we randomly choose whether to insert or remove an edge.
    Edges are only removed between nodes from the same classes,
    and only inserted between nodes from different classes.
    This function perturbs the graph methodically for non-targeted attacks.
    It is used for poisoning/evasion attacks on graphs. The graph is perturbed first
    and then used for training in case of poisoning. For evasion, the original graph
    is trained first and then perturbed and tested on
        :param g: DGL Graph
        :param labels: labels for the nodes
        :param ptb_ratio: structural perturbation ratio
        :return: Perturbed DGL Graph
        if ptb_ratio == 0:
            return g

        total_edges = g.number_of_edges()
        total_nodes = g.number_of_nodes()

        num_perturbations = int(ptb_ratio * (total_edges - total_nodes) / 2)
        # dividing by 2 since dgl graph edges are directional
        print("Number of Perturbations to Graph:", num_perturbations)

        # choose number edges to remove first out of total perturbations
        edge_removal = np.random.choice(2, num_perturbations  )
        num_removal = edge_removal.sum()

        # edge removal first, for edges with same labels
        all_edges = g.edges()
        # all_edges_eids = g.edge_ids(all_edges[0], all_edges[1])
        zipped_all_edges = list(zip(*all_edges))
        # dictionary or edge id storing
        # all_edges_dict = {edge:eid for eid,edge in enumerate(zipped_all_edges)}

        possible_removal_candidates = list(filter(lambda edge:
                                                  labels[edge[0].item()] == labels[edge[1].item()] and
                                                  edge[0] != edge[1],
                                                  zipped_all_edges ))
        remove_edges_src_dst = possible_removal_candidates[:num_removal]
        remove_edge_dst_src = [(e[1],e[0]) for e in remove_edges_src_dst]
        remove_edges = remove_edges_src_dst + remove_edge_dst_src

        edges_src, edges_dst = list(zip(*remove_edges))

        check_edges = (g.has_edges_between(edges_src, edges_dst))
        check_edges_mask = check_edges.numpy().astype(np.bool)

        edges_src = np.array(edges_src)
        edges_dst = np.array(edges_dst)

        edges_src = edges_src[check_edges_mask]
        edges_dst = edges_dst[check_edges_mask]

        remove_edges_eid = g.edge_ids(edges_src, edges_dst)

        # choose remaining edges to be added
        num_additions = num_perturbations - num_removal

        src_nodes = np.random.choice(total_nodes, size=num_additions*2)
        dst_nodes = np.random.choice(total_nodes, size=num_additions*2)

        check_edges = (g.has_edges_between(src_nodes, dst_nodes))
        check_edges_mask = check_edges.numpy().astype(np.bool)

        src_nodes = src_nodes[np.logical_not(check_edges_mask)]
        dst_nodes = dst_nodes[np.logical_not(check_edges_mask)]

        possible_addition_candidates = list(filter(lambda edge:
                                            labels[edge[0]] != labels[edge[1]] and
                                            edge[0] != edge[1],
                                            zip(src_nodes, dst_nodes) ))

        additional_edges = possible_addition_candidates[:num_additions]

        src_nodes, dst_nodes = list(zip(*additional_edges))

        g.add_edges(src_nodes, dst_nodes)
        g.add_edges(dst_nodes, src_nodes)

        return g

If I comment out the line “g.remove_edges(remove_edges_eid)” everything works fine. The problem is seen only when I remove existing edges. Addition of edges is not creating problems.

Hi, the bug have been fixed in Please try our latest version (by install from source or use our nightly build version).